我试图理解Go中创建一个带参数的匿名函数与将该函数作为闭包之间的区别。这是差异的一个例子。
带参数:
func main() {
done := make(chan bool, 1)
go func(c chan bool) {
time.Sleep(50 * time.Millisecond)
c <- true
}(done)
<-done
}
作为封闭:
func main() {
done := make(chan bool, 1)
go func() {
time.Sleep(50 * time.Millisecond)
done <- true
}()
<-done
}
我的问题是,第一种形式何时优于第二种形式?你有没有使用参数来做这种事情?我唯一能看到第一种形式有用的是返回时 func(x, y)
来自另一个功能。
使用闭包与使用函数参数之间的区别与共享相同的变量与获取值的副本有关。考虑下面这两个例子。
在里面 关闭 所有函数调用都将使用存储的值 i
。在任何goroutine有时间打印它的值之前,这个值很可能已经达到3。
在里面 参数 例如,每个函数调用都会传递一个值的副本 i
在进行通话时,我们更有可能获得结果:
关闭:
for i := 0; i < 3; i++ {
go func() {
fmt.Println(i)
}()
}
结果:
3
3
3
参数:
for i := 0; i < 3; i++ {
go func(v int) {
fmt.Println(v)
}(i)
}
结果:
0
1
2
操场: http://play.golang.org/p/T5rHrIKrQv
使用闭包与使用函数参数之间的区别与共享相同的变量与获取值的副本有关。考虑下面这两个例子。
在里面 关闭 所有函数调用都将使用存储的值 i
。在任何goroutine有时间打印它的值之前,这个值很可能已经达到3。
在里面 参数 例如,每个函数调用都会传递一个值的副本 i
在进行通话时,我们更有可能获得结果:
关闭:
for i := 0; i < 3; i++ {
go func() {
fmt.Println(i)
}()
}
结果:
3
3
3
参数:
for i := 0; i < 3; i++ {
go func(v int) {
fmt.Println(v)
}(i)
}
结果:
0
1
2
操场: http://play.golang.org/p/T5rHrIKrQv
何时使用参数
如果您打算更改您不希望在函数中观察到的变量的值,则首选表格是首选。
这是匿名函数在a中的典型情况 for
循环,你打算使用循环的变量,例如:
for i := 0; i < 10; i++ {
go func(i int) {
fmt.Println(i)
}(i)
}
没有传递变量 i
你可能会观察到印刷 10
十次。随着传球 i
,你会看到从中打印的数字 0
至 9
。
何时不使用参数
如果您不想更改变量的值,那么不传递它就更便宜,因此不会创建它的另一个副本。对于大型结构尤其如此。虽然如果稍后更改代码并修改变量,您可能很容易忘记检查其对闭包的影响并获得意外结果。
也有可能是你的情况 做 想要观察对“外部”变量所做的更改,例如:
func GetRes(name string) (Res, error) {
res, err := somepack.OpenRes(name)
if err != nil {
return nil, err
}
closeres := true
defer func() {
if closeres {
res.Close()
}
}()
// Do other stuff
if err = otherStuff(); err != nil {
return nil, err // res will be closed
}
// Everything went well, return res, but
// res must not be closed, it will be the responsibility of the caller
closeres = false
return res, nil // res will not be closed
}
在这种情况下 GetRes()
是打开一些资源。但在返回之前,必须完成其他可能也会失败的事情。如果那些失败, res
必须关闭,不得退回。如果一切顺利, res
不得关闭并退回。