Characteristics of go language different from other languages

Time:2022-5-8
catalogue
  • 1. Go always includes binaries in the build
  • 2. There are no managed services for go
  • 3. Go is called by value
  • 4. ‘defer’ keyword
  • 5. Go adopts the best features of functional programming
  • 6. Go has an implicit interface
  • 7. Error handling
  • 8. Concurrency
  • 9. Go standard library

preface:

With the development of programming language, go is still very young. It was first released on November 10, 2009. Its creatorRobert Griesemer Rob Pike andKen ThompsonstayGoogle Work, where the challenge of large-scale expansion inspired them to design go as a fast and effective programming solution, which has a large code base, is managed by multiple developers, has strict performance requirements, and spans multiple networks and processing cores. The founders of go also took the opportunity to learn the advantages, disadvantages and vulnerabilities of other programming languages when creating their new language. The result is a clean, clear and practical language with a relatively small set of commands and functions.

1. Go always includes binaries in the build

Go runtime provides services such as memory allocation, garbage collection, concurrency support and network. It is compiled into each go binary. This is different from many other languages, many of which use virtual machines that need to be installed with programs to work properly.

Including the runtime directly in binary files makes it easy to distribute and run go programs, and avoids the incompatibility between the runtime and programs.PythonRuby andJavaScript Virtual machines in other languages are not optimized for garbage collection and memory allocation, which explains the superior speed of go compared with other similar languages. For example, go stores as much as possible in the stack, where the data is arranged in order for faster access than the heap. It will be described in detail later.

The last thing about go’s static binaries is that they start very fast because there is no need to run external dependencies. If you use services such as Google App Engine, this is aGoogle Cloud Platform as a service running on, which can reduce your application to zero instances to save cloud costs, which will be very useful. When a new request is received,App Engine You can start an instance of the Go program in the blink of an eye. stayPython The same experience in or node usually leads to a wait of 3-5 seconds (or more), because the required virtual environment will also start with the new instance.

2. There are no managed services for go

In order to access published Go programs, developers do not rely on centrally hosted services, such as JavaMaven CentralorJavaScriptNPM registry for. Instead, the project passes through its source code repository (most commonlyGithub)Share. The go install command line allows libraries to be downloaded in this way. Why do I like this feature? I always thought it was likeMaven CentralPIP Depending on the installation of NPM, there may be terrible heartbeats and errors in the installation of abstract dependencies, but such dependencies will inevitably lead to terrible heartbeats.

In addition, providing modules to others is as simple as putting them into a version control system, which is a very simple way to distribute programs.

3. Go is called by value

In go, when you provide an original value (number, Boolean or string) or a structure (rough equivalent of class object) as the parameter of the function, go will always copy the value of the variable.

stayJavaPython andJavaScript In many other languages, primitives are passed by value, but objects (class instances) are passed by reference, which means that the receiving function actually receives a pointer to the original object rather than a copy of it. Any changes made to the object in the receive function are reflected in the original object.

In go, structures and primitives are passed by value by default. You can choose to pass pointers by using the asterisk operator:

?
1
2
3
4
5
6
// Pass by value
func MakeNewFoo(f Foo ) (Foo, error) {
   f.Field1 = "New val"
   f.Field2 = f.Field2 + 1
   return f, nil
}

The above function receives a copy of Foo and returns a new foo object.

?
1
2
3
4
5
6
// Pass by reference
func MutateFoo(f *Foo ) error {
   f.Field1 = "New val"
   f.Field2 = 2
   return nil
}

The above function takes a pointer to Foo and changes the original object.

This clear distinction between call by value and call by reference makes your intention obvious and reduces the possibility that the calling function inadvertently changes the incoming object (clenching when it shouldn’t happen (which is difficult for many novice developers to do).

As MIT concludes, “variability makes it more difficult to understand what your program is doing and to enforce the contract.”

In addition, calling by value significantly reduces the work of the garbage collector, which means faster applications and more memory efficient. The conclusion of this article is that pointer tracing (retrieving pointer values from the heap) is 10 to 20 times slower than retrieving values from consecutive stacks. A good rule of thumb to keep in mind is that the fastest way to read from memory is sequential reading, which means minimizing the number of pointers randomly stored in RAM.

4. ‘defer’ keyword

stayNodeJS After I started using KNEX JS, I will manually manage the database connections in my code by creating a database pool, and then open a new connection from the pool in each function. Once the required database crud function has been completed.

This is a bit like a maintenance nightmare, because if I don’t release the connection at the end of each function, the number of unreleased database connections will slowly increase until there are no more available connections in the pool, and then interrupt the application.

The reality is that programs often need to release, clean up and dismantle resources, files, connections, etc., so go introducesdeferKeywords are an effective way to manage these.

Any todeferThe first statement will delay the call to it until the surrounding function exits. This means that you can put the cleanup / disassembly code at the top of the function (obviously), knowing that it will do so once the function is complete.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func main() {                       
    if len(os.Args) < 2 {  
        log.Fatal("no file specified")
    
    f, err := os.Open(os.Args[1])                       
    if err != nil {                        
        log.Fatal(err)                       
    }                       
    defer f.Close()                       
    data := make([]byte, 2048)                       
    for {                        
        count, err := f.Read(data)                                              
        os.Stdout.Write(data[:count])                       
        if err != nil {                         
            if err != io.EOF {                          
                log.Fatal(err)                         
            }                         
            break                        
        }                       
    }                      
}

In the above example, the file closing method is delayed. I like this mode of declaring your housekeeping intention at the top of the function, then forget it and know that once the function exits, it will finish its work.

5. Go adopts the best features of functional programming

Functional programming is an efficient and creative paradigm. Fortunately, go adopts the best features of functional programming.In go:

  • Functions are values, which means that they can be added to the map as values, passed to other functions as parameters, set as variables, and returned from functions (called “high-order functions”, which are often used to create middleware patterns in go).
  • Anonymous functions can be created and called automatically.
  • Functions declared within other functions allow closures (functions declared within functions can access and modify variables declared in external functions). In the idiomatic go, closures are widely used to limit the scope of functions and set the state of functions that are then used in their logic.

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
func StartTimer (name string) func(){
    t := time.Now()
    log.Println(name, "started")
    return func() {
        d := time.Now().Sub(t)
        log.Println(name, "took", d)
    }
}
func RunTimer() {
    stop := StartTimer("My timer")
    defer stop()
    time.Sleep(1 * time.Second)
}

The above is an example of closure. “StartTimer‘function returns a new function that can access the’t’ value set in its birth range through closure. This function can then compare the current time with the value of “t” to create a useful timer. Thanks to mat ryer for this example.

6. Go has an implicit interface

Anyone who has read aboutSOLIDAnyone in the literature of coding and design patterns may have heard of the mantra “priority combination is better than inheritance”. In short, this means that you should decompose your business logic into different interfaces rather than relying on hierarchical inheritance of attributes and logic from the parent class.

Another popular approach is “programming for interfaces, not implementation”: an API should only publish a contract (its method signature) for its intended behavior, not details on how to implement it.

Both show the importance of interface in modern programming.

Therefore, it is not surprising that go supports interfaces. In fact, interfaces are the only abstract types in go.

However, unlike other languages, the interface in go is not implemented explicitly, but implicitly. A concrete type does not declare that it implements an interface. On the contrary, if the method set set for the specific type contains all the method sets of the underlying interface, go considers that the object implementsinterface

This implicit interface implementation (formally called structural types) allows go to enforce type safety and decoupling, maintaining most of the flexibility shown in dynamic languages.

In contrast, explicit interfaces bind the client and implementation together. For example, replacing dependencies in Java is much more difficult than in go.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// This is an interface declaration (called logic)
type Logic interface {
    Process (data string) string
}
 
type LogicProvider struct {}
// This is the method struct named "process" on logicprovider
 func (lp LogicProvider) Process (data string) string {
    // Business logic
}
// This is a client structure with a logic interface as an attribute
type Client struct {
    L Logic
}
func(c Client) Program() {
    // Get data from somewhere
    cLProcess(data)
}
func main() {
    c := Client {
        L: LogicProvider{}, 
     }
    c.Program()
}

LogicProvider There is no statement in that it complies withLogicInterface. This means that clients can easily replace their logical provider in the future, as long as the logical provider contains all the method sets of the underlying interface (logic).

7. Error handling

Error handling in go is very different from other languages. In short, go handles errors by returning a value of type error as the last return value of the function.

When the function executes as expected, the error parameter returns nil, otherwise it returns the error value. Call the function and then check the error return value and handle the error, or throw your own error.

?
1
2
3
4
5
6
7
8
9
// Function returns an integer and an error
func calculateRemainder(numerator int, denominator int) ( int, error ) {
   //
   if denominator == 0 {
      return 9, errors.New("denominator is 0"
    }
   // No error returned
   return numerator / denominator, nil
 }

Go works this way for a reason: it forces the coder to consider exceptions and handle them correctly. conventionaltry-catch Exceptions also add at least one new code path to the code and indent the code in a way that is difficult to follow. Go prefers to treat the “happy path” as non indented code, identifying and returning any errors before the “happy path” is completed.

8. Concurrency

It can be said that it is the most famous feature of go. Concurrency allows processing to run in parallel on the number of available cores on the machine or server. Concurrency makes the most sense when individual processes are not interdependent (do not need to run sequentially) and time performance is critical. This is usually the case with I / O requirements, where the speed of reading or writing to disk or network is several orders of magnitude slower than all processes except the most complex in memory processes. The “go” keyword before the function call will run the function at the same time.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
func process(val int) int {
   // Do something with Val
}
// about'in' Run the process function at the same time,
// And read the result of process to'out'
 func runConcurrently(in <-chan int, out chan<- int){
   go func() {
       for val := range in {
            result := process(val)
            out <- result  
       }
   }
}

Concurrency in go is an in-depth and fairly advanced function, but where it makes sense, it provides an effective way to ensure the best performance of the program.

9. Go standard library

Go has a concept of “including battery”. Many requirements of modern programming languages are incorporated into the standard library, which makes the life of programmers easier. As mentioned earlier, go is a relatively young language, which means that many problems / requirements of modern applications can be met in the standard library.

On the one hand, go provides world-class support for network (especially http / 2) and file management. It also provides native JSON encoding and decoding. Therefore, setting up the server to handle HTTP requests and return responses (JSON or other) is very simple, which explains the role of go based on rest HTTP Web Popularity in service development.

just asMat RyerIt is also pointed out that the standard library is open source and is a great way to learn go best practices.

This is the end of this article about the nine features of go that are different from other languages. For more information about the features of go that are different from other languages, please search the previous articles of developeppaper or continue to browse the relevant articles below. I hope you will support developeppaper in the future!

Recommended Today

Use of vuex and map method

Vuex Concept: a Vue plug-in that implements centralized state (data) management in Vue. It centrally manages (reads / writes) the shared state of multiple components in Vue applications. It is also a way of communication between components, and is applicable to the communication between any components Usage scenario: multiple components need to share data Build […]