In Go language, function is a first-class citizen, and function type is also a first-class data type. This paper mainly introduces the high-level usage of golang function (callback, function type, anonymous function, closure function and high-order function).
In go language, function is a first-class citizen, and function type is also a first-class data type. It is necessary to master various usages of go function. The basic usages are not repeated here. Some advanced usages are mainly introduced below.
Callback
Functions can be passed as parameters of other functions, and then called and executed in other functions, which is generally called callback. Here is a simple example:
package main import ( "fmt" ) func main() { callback(1, Add) //The sum of 1 and 2 is: 3 } func Add(a, b int) { fmt.Printf("The sum of %d and %d is: %d\n", a, b, a+b) } func callback(y int, f func(int, int)) { f(y, 2) // this becomes Add(1, 2) }
Function type
In Go language, function type is also a first-class data type. In short, this means that functions can not only be used to encapsulate code, partition functions and decoupling logic, but also be embodied as ordinary values, transfer, assign variables, make type judgment and conversion between other functions, just like the values of slices and dictionaries.
The deeper meaning is that function values can become independent logical components (or functional modules) that can be propagated at will.
For function types, it is an important tool for templating a group of inputs and outputs. It is lighter and more flexible than interface types, and its value has become a hot replaceable logical component. For example, the following code:
package main import "fmt" type Printer func(contents string) (n int, err error) //Note how it is written here. To the right of the name of the type declaration is the func keyword, so we can know that this is a function type declaration. func printToStd(contents string) (bytesNum int, err error) { return fmt.Println(contents) } func main() { var p Printer p = printToStd p("something") }
Here, first declare a function type called Printer; Then, the signature of the function printToStd declared below is consistent with that of Printer, so the former is an implementation of the latter, even if their names and some result names are different. Then, the code in the main function assigns the printToStd function to the variable p of Printer type, and successfully calls it.
Note: function parameters, return values, and their types are collectively referred to as function signatures. As long as the order and type of elements in the parameter list and result list of the two functions are consistent, we can say that they are the same functions, or functions that implement the same function type.
Anonymous function
Anonymous function is a function implementation without defining a function name. It consists of a function declaration without a function name and a function body
// Anonymous functions without function names are directly assigned to a variable: who := func (name string, age int) (string, int) { return name, age } a,b := who("age",20) fmt.Println(a,b) //Runsen 20
Closure function
In short, when an anonymous function references a variable in an external scope, it becomes a closure function. Closure function is the core of functional programming language.
Closure refers to a variable outside the function body. This variable has a special term called free variable. This function can access and assign values to the referenced variables; In other words, the function is "bound" to the variable. When there is no closure, the function is a one-time sale. After the function is executed, the value of the variable in the function can no longer be changed (memory should be released); With closures, the function becomes the value of a variable. As long as the variable is not released, the function will always be in a state of survival and exclusive enjoyment. Therefore, the value of the variable in the function can be changed later (because it will not be recycled by go and will always be cached there).
What is the point of using closures? It is mainly to narrow the scope of variables and reduce the pollution to global variables.
For example, implement such a calculation function: a number starts from 0, each time add its own value and the current number of cycles (the current number of times, the cycle starts from 0 to 9, a total of 10 times), and then * 2, so as to iterate 10 times.
Write this when there is no closure:
func adder(x int) int { return x * 2 } func main() { var a int for i := 0; i < 10; i ++ { a = adder(a+i) fmt.Println(a) } }
If you use closures, you can write as follows:
func () func(int) int { res := 0 return func(x int) int { res = (res + x) * 2 return res } } func main() { a := adder() for i := 0; i < 10; i++ { fmt.Println(a(i)) } }
As can be seen from the above example, there are three benefits:
1. It is not a one-time consumption. It can be called repeatedly after being declared by reference. At the same time, the variables are only limited in the function. At the same time, each call does not start from the initial value (variables are stored in the function for a long time)
In fact, it's a bit like using object-oriented to instantiate a class, so that all methods and properties in this class are private and exclusive to someone. But it is lighter than object-oriented
2. After the closure is used, the main function becomes simple. The algorithm is encapsulated in a function, so that the main function omits the trouble of a=adder(a+i)
3. Variable pollution is less, because if closures are not used, variables will be declared outside the function in order to transfer values to the function, but the declared variables will be mistakenly changed by other functions or codes below.
Higher order function
What is a higher order function? In short, higher-order functions can satisfy the following two conditions:
1. Accept other functions as parameters;
2. Return other functions as results.
As long as any one of these characteristics is satisfied, we can say that this function is a high-order function. Higher order function is also an important concept and feature in functional programming.
For example, I want to write the calculate function to realize the addition, subtraction, multiplication and division between two integers, but I hope that the two integers and specific operations are given by the caller of the function. How should such a function be written.
First, let's declare a function type called operate. It has two parameters and a result, both of which are of type int. operate is passed in as a parameter.
type operate func(x, y int) int
Then declare a function type called genCalculator as the return result of the function.
type calculateFunc func(x int, y int) (int, error)
In this way, when we pass in different operators, we will perform different operations and get the corresponding results. The complete code is as follows:
package main import ( "errors" "fmt" ) type operate func(x, y int) int type calculateFunc func(x int, y int) (int, error) func genCalculator(op operate) calculateFunc { return func(x int, y int) (int, error) { if op == nil { return 0, errors.New("invalid operation") } return op(x, y), nil } } func main() { x, y := 3, 4 op := func(x, y int) int { return x + y } add := genCalculator(op) // addition result, err := add(x, y) fmt.Printf("The addition result: %d (error: %v)\n", result, err) op1 := func(x, y int) int { return x * y } multi := genCalculator(op1) //multiplication result, err = multi(x, y) fmt.Printf("The multiplication result: %d (error: %v)\n", result, err) }