golang闭包原理、用途、示例代码详解


1、Go语言支持闭包
2、Go语言能通过escape analyze识别出变量的作用域,自动 将变量在堆上分配。将闭包环境变量在堆上分配是Go实现闭包的基础。
3、返回闭包时并 不是单纯返回一个函数,而是返回了一个结构体,记录下函数返回地址和引用的环境中的变量地址。

用途

函数式编程,匿名函数。

示例一

package main

import "fmt"

func adder() func(int) int {
	sum := 0
	return func(x int) int {
		fmt.Printf("sum addr=%p, x addr=%p\n", &sum, &x)
		sum += x
		return sum
	}
}

func main() {
	pos, neg := adder(), adder()
	fmt.Printf("pos addr=%p, neg addr=%p\n", &pos, &neg)
	for i := 0; i < 10; i++ {
		fmt.Println(
			pos(i),
			neg(-2*i),
		)
	}
}

输出如下:

pos addr=0xc000006028, neg addr=0xc000006030
sum addr=0xc0000180d8, x addr=0xc0000180f8
sum addr=0xc0000180f0, x addr=0xc000018120
0 0
sum addr=0xc0000180d8, x addr=0xc000018130
sum addr=0xc0000180f0, x addr=0xc000018138
1 -2
sum addr=0xc0000180d8, x addr=0xc000018160
sum addr=0xc0000180f0, x addr=0xc000018168
3 -6
sum addr=0xc0000180d8, x addr=0xc000018190
sum addr=0xc0000180f0, x addr=0xc000018198
6 -12
sum addr=0xc0000180d8, x addr=0xc0000181c0
sum addr=0xc0000180f0, x addr=0xc0000181c8
10 -20
sum addr=0xc0000180d8, x addr=0xc0000181f0
sum addr=0xc0000180f0, x addr=0xc0000181f8
15 -30
sum addr=0xc0000180d8, x addr=0xc000018220
sum addr=0xc0000180f0, x addr=0xc000018228
21 -42
sum addr=0xc0000180d8, x addr=0xc000018250
sum addr=0xc0000180f0, x addr=0xc000018258
28 -56
sum addr=0xc0000180d8, x addr=0xc000018280
sum addr=0xc0000180f0, x addr=0xc000018288
36 -72
sum addr=0xc0000180d8, x addr=0xc0000182b0
sum addr=0xc0000180f0, x addr=0xc0000182b8
45 -90

因为pos和neg都调用了adder()参数,返回了不同的闭包,所以sum在堆上分配的地址空间也不同;
所以针对pos(i)是求sum=sum+i,即0+0=0,0+1=1, 1+2=3,3+3=6…
neg是求sum=sum+(-2i),即0+(-20)=0,0+(-21)=-2,-2+(-22)=-6…

示例二

package main

import "fmt"

func main() {
	var flist []func()
	for i := 0; i < 3; i++ {
		fmt.Printf("A: addr=%p, value=%d\n", &i, i)
		flist = append(flist, func() {
			fmt.Printf("B: addr=%p, value=%d\n", &i, i)
		})
	}

	for _, f := range flist {
		f()
	}
}

输出如下:

A: addr=0xc0000180d8, value=0
A: addr=0xc0000180d8, value=1
A: addr=0xc0000180d8, value=2
B: addr=0xc0000180d8, value=3
B: addr=0xc0000180d8, value=3
B: addr=0xc0000180d8, value=3

这个比较好理解,三个匿名函数闭包中的i是同一个变量i,在堆上是同一个,最后i的值为3,所以三次都输出3。

示例三

package main

import "fmt"

func main() {
	var flist []func()
	for i := 0; i < 3; i++ {
		//给i变量重新赋值
		i := i
		fmt.Printf("A: addr=%p, value=%d\n", &i, i)
		flist = append(flist, func() {
			fmt.Printf("B: addr=%p, value=%d\n", &i, i)
		})
	}
	for _, f := range flist {
		f()
	}
}

输出结果如下:

A: addr=0xc0000180d8, value=0
A: addr=0xc0000180f8, value=1
A: addr=0xc000018118, value=2
B: addr=0xc0000180d8, value=0
B: addr=0xc0000180f8, value=1
B: addr=0xc000018118, value=2

i被重新赋值,传入闭包函数的i为新的地址,所以三个闭包函数分别为1,2,3

参考

Go语言中的闭包

Golang中闭包的实现原理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

进击云原生

众筹一元植发

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值