函数的闭包 在GO
语言中,是支持函数的闭包的,具体用法如下例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 func main () { f := liner(10 ) fmt.Println(f(1 )) fmt.Println(f(2 )) } func liner (x int ) func (int ) int { fmt.Printf("%v\n" , &x) return func (y int ) int { fmt.Printf("%v\n" , &x) return x + y } }
结果为:
1 2 3 4 5 0xc000062008 0xc000062008 11 0xc000062008 12
对于闭包,自己的理解就是:在函数中的匿名函数,使用了外部函数的变量。外部函数调用之后,返回的函数,在使用过程中,外部函数的变量一直未被销毁,感觉上就像是外部函数的变量,一直被内部的匿名函数给”包裹”,始终拥有外部函数变量的引用。
从打印结果看,外部变量的地址和匿名函数调用时,使用的x是同一变量。
注意: 在循环中使用defer
1 2 3 4 5 6 7 8 9 import "fmt" func main () { for i := 0 ; i < 3 ; i ++ { defer func () { fmt.Println(i) }() } }
这段代码的原本的想要的结果为:0 1 2
但是上述代码执行的结果为:
为什么会这样呢?其实这也是闭包的使用,在defer函数使用i其实是对变量i
的引用,当循环结果后,i的值为3,既然defer修饰的函数是对变量i
的引用,所以所有的defer函数都打印出了3.
所以,在使用defer修饰的匿名函数时,一定要注意,慎重使用所在函数的变量。
为了加深印象, 打印如下代码的结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 func main () { var fs = [4 ]func () {} for i := 0 ; i < 4 ; i++ { defer fmt.Println("defer i = " , i) defer func () { fmt.Println("defer_closure i = " , i) }() fs[i] = func () { fmt.Println("closure i = " , i) } } for _, f := range fs { f() } }
结果为:
1 2 3 4 5 6 7 8 9 10 11 12 closure i = 4 closure i = 4 closure i = 4 closure i = 4 defer_closure i = 4 defer i = 3 defer_closure i = 4 defer i = 2 defer_closure i = 4 defer i = 1 defer_closure i = 4 defer i = 0