课程地址 go-class-slides/xmas-2020 at trunk · matt4biz/go-class-slides (github.com)
主讲老师 Matt Holiday
09-Closures
变量的生命周期可以超过变量声明上下文的范围
左侧 f 只是函数指针,右侧 f 则是闭包。
Slice
需要一个特定的闭包签名函数。在闭包的上下文中,我唯一传递给我的闭包是 i、j 他们是整数,ss 也是这个函数的一部分虽然没有被明确传入。
package main
import \"fmt\"
func do(d func()) {
d()
}
func main() {
for i := 0; i < 4; i++ {
v := func() {
fmt.Printf(\"%d @ %p\\n\", i, &i)
}
do(v)
}
}
0 @ 0xc000016088
1 @ 0xc000016088
2 @ 0xc000016088
3 @ 0xc000016088
package main
import \"fmt\"
func main() {
s := make([]func(), 4)
for i := 0; i < 4; i++ {
s[i] = func() {
fmt.Printf(\"%d @ %p\\n\", i, &i)
}
}
for i := 0; i < 4; i++ {
s[i]()
}
}
4 @ 0xc000016088
4 @ 0xc000016088
4 @ 0xc000016088
4 @ 0xc000016088
当封闭 i
变量时,每个闭包需要一个引用。四个匿名函数引用的都是同一个 i
,在第一个循环退出后,i
值为 4。i
并没有被垃圾回收,因为它仍被 4
个匿名闭包函数所引用。每次打印都是 4
比如传入一个闭包函数作为回调函数的时候,所引用的值在回调执行前会发生改变,那会出现大问题。
在第一个循环内创建一个新变量,每次循环声明初始化一个新变量,每个闭包函数会引用这个新变量,每个 i2
地址不一样。
for i := 0; i < 4; i++ {
i2 := i // closure capture
s[i] = func() {
fmt.Printf(\"%d @ %p\\n\", i, &i)
}
闭包是一种函数,调用具有来自函数外部的附加数据。例如数据来自另一个函数的范围,并且它通过引用封闭(封盖)。被封闭参数有点像参数,但它并不是,它允许我们函数使用那些不能用参数传递的额外数据,例如有些被其他类型固定的数据而无法被传递的数据。我们需要注意 gotcha
,因为闭包通过引用封闭,如果闭包是异步执行的,那么我封闭(封盖)的变量可能会发生改变。正如前面的例子,修复方法就是创建一个对应的本地副本,让闭包函数关闭(封盖)本地副本,这样副本的值就固定了。
来源:https://www.cnblogs.com/linxiaoxu/p/16101386.html
本站部分图文来源于网络,如有侵权请联系删除。