面试题答案
一键面试可能出现的内存管理问题
- 变量共享导致结果非预期:由于闭包引用的是同一个迭代变量,当闭包实际执行时,循环可能已经结束,迭代变量的值已经是循环结束后的最终值,这会导致所有闭包操作的是同一个最终值,而不是每次迭代时的预期值。例如:
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
,因为闭包中引用的 i
是同一个变量,在循环结束后 i
的值为 3
。
2. 内存泄漏风险:如果闭包持有对较大对象的引用,且这些闭包在循环结束后长时间存活,可能导致这些对象无法被垃圾回收,从而造成内存泄漏。
避免问题以优化内存使用的方法
- 通过参数传递:在创建闭包时,将迭代变量作为参数传递给闭包,这样每个闭包就会有自己独立的变量副本。例如:
package main
import (
"fmt"
)
func main() {
var funcs []func()
for i := 0; i < 3; i++ {
index := i
funcs = append(funcs, func() {
fmt.Println(index)
})
}
for _, f := range funcs {
f()
}
}
这里通过 index := i
创建了一个新的局部变量 index
,每个闭包引用的是 index
,这样就会输出预期的 0 1 2
。
2. 使用函数参数形式:直接在闭包定义时将迭代变量作为参数传入。例如:
package main
import (
"fmt"
)
func main() {
var funcs []func()
for i := 0; i < 3; i++ {
funcs = append(funcs, func(j int) func() {
return func() {
fmt.Println(j)
}
}(i))
}
for _, f := range funcs {
f()
}
}
在这个例子中,通过一个立即执行的函数将 i
作为参数 j
传递给内部闭包,同样可以达到每个闭包有独立变量副本的效果。