0
点赞
收藏
分享

微信扫一扫

Go匿名函数和闭包


文章目录

  • ​​Go匿名函数和闭包​​
  • ​​闭包的定义和实现​​
  • ​​延迟调用和闭包​​
  • ​​闭包的实现​​

Go匿名函数和闭包

闭包的定义和实现

如何定义闭包?

闭包是引用了自由变量的函数,这个自由变量将和这个函数一同存在,即使离开了创造他的环境,闭包是由函数及其相关引用环境组成的实体,可以理解为一个函数“捕获”了和它处于同一作用域的其他变量。“捕获”的本质就是引用传递而非值传递。

简单的闭包就是在函数中返回匿名函数

type MyFunc func() int

// 简单的闭包:在函数中返回匿名函数
func Test() MyFunc{
return func() int {
return 1
}
}

func MyTest()int {
myFunc := Test()
return myFunc()
}

关于闭包环境变量的说明

// 外部环境修改
func Test3(n int) MyFunc2 {
n++
return func() {
fmt.Println(n)
}
}

// 闭包环境修改
func Test4(n int) MyFunc2{
return func() {
n++
fmt.Println(n)
}
}

func MyTest2(){
test3 := Test3(1) // 在闭包函数外部执行n++,没有在闭包函数内部执行,所以每次都是2
test3() // 2
test3() // 2

fmt.Println("-----------------")

test4 := Test4(1) // 在闭包函数内部执行n++,此时也是值传递,只是这个值是n的地址值
test4() // 2
test4() // 3

test44 := Test4(1) // 重新拿到一个新的闭包函数环境
test44() // 2
}

所以,通过上述的例子可以证明,内函数对外函数的变量的修改,是对变量的引用,因为这样,导致原来在栈上分配的外函数变量逃逸到了堆上进行分配,当外函数结束了,这个变量也不会马上被销毁,相当于延长了外函数的生命周期,当重新调用包含闭包函数的函数时,此时会得到一份新的闭包函数,函数环境也是新的.

延迟调用和闭包

go中的延迟调用使用的是defer,defer在函数返回时执行defer后定义的匿名函数

func MyTest4(){
x, y := 1, 2

defer func(a int) {
fmt.Printf("x:%d,y:%d\n", a, y) // y 为闭包引用 x:1,y:102
}(x) // 复制 x 的值,defer执行时使用的是当时拷贝过来的x

x += 100
y += 100
fmt.Println(x, y) // x:101,y:102
}

func MyTest5(){
x, y := 1, 2

defer func() {
fmt.Printf("x:%d,y:%d\n", x, y) // x,y为闭包引用 x:101,y:102
}()

x += 100
y += 100
fmt.Println(x, y) // x:101,y:102
}

  • 对于defer中匿名函数的传参,使用的是值传递,在执行时会使用一开始拷贝好的值
  • 对于defer中匿名函数对外部变量的修改,是对其引用的修改

由于闭包的存在,Golang中使用匿名函数的时候要特别注意区分清楚引用传递和值传递。根据实际需要,我们在不需要引用传递的地方通过匿名函数参数赋值的方式实现值传递。

func main() {
fmt.Println("----------------引用传递----------------")
for i := 0; i < 10; i++ {
go func() {
fmt.Println(i)
}()
}
time.Sleep(10 * time.Millisecond)

fmt.Println("----------------值传递----------------")
for i := 0; i < 10; i++ {
go func(x int) {
fmt.Println(x)
}(i)
}
time.Sleep(10 * time.Millisecond)

return
}

// 输出
----------------引用传递----------------
1
10
10
10
10
10
10
10
10
10
----------------值传递----------------
4
9
1
6
5
7
2
3
8
0

闭包的实现

闭包说白了就是一个有状态的函数。

Go 实现闭包是通过返回一个如下的结构来实现的:

type Closure struct {
F uintptr
env *Type
}

F 是返回的匿名函数指针,env 是对外部环境变量的引用集合


举报

相关推荐

0 条评论