[GO Language 04-1] GoLanguage on function definition, closure function, scope, defer keywords in detail

Posted by Shai-Hulud on Fri, 04 Feb 2022 18:41:01 +0100

Functional encapsulation in the Go language is done through functions, and different structures can be unified through interfaces. Combined with reflection characteristics, large and complex projects can be developed.

1. Definition of functions

The Go language supports object-oriented programming, but functions are the basic elements of the Go language.
Go Language functions are classified into anonymous and named functions

//named function
func main(a int) int {
	return a * a
}
main(11)

//Anonymous function
var nua = func(a int) int {
	return a * a
}
nua(12)

2. Closure

Anonymous functions can be assigned to one variable or written directly inside another:

func main() {
	f := double()
	fmt.Println(f())
	fmt.Println(f())
	fmt.Println(f())
	fmt.Println(f())
}

func double() func() int  {
	// 1. The default initial value of type int is 0
	var r int
	// 2. Return an anonymous function
	return func() int {
		r++
		return r*2
	}
}

Notice here that the return value is of type func() int and returns an anonymous function.
The anonymous function here is the closure function.
The output here is:

2
4
6
8

Strangely, why not be 2222? This is the difference between a closure function and a normal function.
Anonymous functions compile by wrapping variables into their own functions, thus crossing the scope limit and allowing the variable r to persist, which is called a closure.

To add:

1. A closure packages a function with the variable it accesses, and no longer cares about the original scope of the variable. The closure itself can be viewed as a separate object.
2. The biggest difference between a closure function and a normal function is that parameters are not passed by value but by reference, so a closure function can operate on variables other than its own function.
3. Closure functions operate on external variables so that they cannot be released for recycling, thus crossing the scope limit.

3. Scope

Compare the two sets of codes:

var funcList []func()
for i:=0; i<3; i++{
	funcList = append(funcList,func(){
		fmt.Println(i)
	})
}
for _,f := range funcList{
	f()
}

Run result:

3
3
3
var funcList2 []func()
for i:=0;i<3;i++{
	j := i  //<<================================The difference
	funcList2 = append(funcList2,func(){
		fmt.Println(j)
	})
}
for _,f := range funcList2{
	f()
}

Run result:

0
1
2

The results of the two code blocks are quite different because the anonymous function uses a pointer to an external variable, not a value copy.
In the for loop, variable i is a shared variable, and each loop adds 1 to the value stored in the principle. After three cycles, i stores a value of 3.
In the first code block, although the function is printed three times, it is only printed three times.
In the second block of code, an extra local variable j is declared each time it is executed within the loop, which is equivalent to storing different values of i each time.

Be careful:
Local variable names and global variable names in the Go language can be duplicated. When duplicated, duplicate variables are treated as local variables by default.

	var funcList3 []func(int)
	for i:=0;i<3;i++{
		funcList3 = append(funcList3,func(i int){
			fmt.Println(i)
		})
	}
	for i,f := range funcList3{
		fmt.Println("===========",i)
		f(i)
	}

Run result:

=========== 0
0
=========== 1
1
=========== 2
2

Closure functions keep variables they use in memory, which prevents them from being recycled in time, and may modify the values of variables used by parent functions through closures.

4. Return Values and Variable Length Parameters

4.1, Return multiple values

func swap(a,b int) (int,int) {
	return b,a
}
fmt.Println(swap(1,2))

4.2, Input parameter is variable length parameter

func sum(a int,others ...int) int {
	for _,v := range others{
		a += v
	}
	return a
}
fmt.Println(sum(1,2,3,4,5,6,7,8,9,10)) // 55

argus := []int{2,3,4,5,6,7,8,9,10}
// Plus... Resolve the values inside the slice and pass them
fmt.Println(sum(1,argus...)) // 55

4.3, Empty interface as variable length parameter

func print(a ...interface{})  {
	fmt.Println(a...)
}
// Empty interface defines variable length parameters
args := []interface{}{1234,"abcd"}
print(args) // [1234 abcd]
print(args...) // 1234 abcd plus... Resolve the values inside the slice and pass them

In the Go language, parameter transfer of functions only passes values in one way, even with pointers, but also with values.

It is important to emphasize how the parameters of a function are passed. In the Go language, function parameters can only be passed by value, not by reference. Although a pointer can be used, it essentially passes the address the pointer points to, because it accesses the value within the address, it is mistaken for reference passing.

Slices, for example, make it feel like functions use reference passing when processing slices, because they contain addresses, so they can be accessed directly.

In addition, the length and capacity contained in the slice are also passed to the function by value. If the length or capacity is modified within the function, the slice outside the function will not be received, so another slice needs to be returned, which is why the append function will return slices every time.

5. defer keywords

In practical applications, ensure that when errors occur during the execution of functions, some necessary things can be handled in time, such as closing the connection, etc. These functions can be achieved by using the defer keyword.

The defer keyword is used to free resources and is called before the function returns, even if the function crashes, before the end.

The general usage is as follows:

f,err := os.Open(fileName)
if err != nil{
	panic(err)
}
defer f.Close()

After this, the code that is processed later will close the file before it is finished, even if an error occurs.

There can also be multiple defers within a function that are called in a stack-like manner, i.e. written before the meeting and then called (executed first by the innermost defer statement).

Topics: Go Blockchain Back-end