面试题答案
一键面试匿名函数访问外部作用域变量
在Go语言中,匿名函数可以直接访问外部作用域的变量,因为Go语言的匿名函数是闭包。闭包是一个函数值,它引用了其函数体之外的变量。当这个函数被调用时,被引用的变量会被保留,即使外部作用域已经结束。
代码示例及作用域陷阱
package main
import (
"fmt"
)
func main() {
var funcs []func()
for i := 0; i < 3; i++ {
funcs = append(funcs, func() {
fmt.Println(i)
})
}
for _, f := range funcs {
f()
}
}
在上述代码中,预期输出是 0 1 2
,但实际输出是 3 3 3
。这就是一个作用域陷阱。原因是在 for
循环中,i
是同一个变量,匿名函数捕获的是 i
的引用,而不是 i
的值。当 for
循环结束时,i
的值已经变为 3
,所以当所有匿名函数执行时,输出的都是 3
。
解决这个问题的一种方法是在每次循环时创建一个新的变量来保存 i
的值:
package main
import (
"fmt"
)
func main() {
var funcs []func()
for i := 0; i < 3; i++ {
j := i
funcs = append(funcs, func() {
fmt.Println(j)
})
}
for _, f := range funcs {
f()
}
}
这样修改后,每次循环都会创建一个新的 j
变量,每个匿名函数捕获的是不同的 j
值,输出就会是预期的 0 1 2
。