5. Go 闭包

函数的闭包

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 但是上述代码执行的结果为:

1
2
3
3
3
3

为什么会这样呢?其实这也是闭包的使用,在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)// 保存了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
# Go
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×