知识卡片
闭包捕获有成本
内容
闭包引用外部变量时,编译器要决定按值捕获还是按地址捕获;变量生命周期被延长时可能逃逸到堆。闭包的优雅背后,是对象生命周期的重新计算。
参考来源
- 位置:《Go语言底层原理剖析》第9章《函数与栈》9.2节《函数闭包与陷阱》(原理见第1章1.7节《变量捕获》)
- 结论依据:原文用 for range 闭包引用 val 的经典陷阱说明"由于当前val值引用的是同一个地址的数据,所以在range循环的过程中,会不断在val地址中更新数据……而在闭包中,由于引用了外部变量val,所以在访问时会获取val地址中的值,可能会获取最后放入其中的值";第1章进一步说明闭包变量捕获需要区分值引用与地址引用,被延迟赋值的变量须按地址引用捕获,因此可以推出"闭包捕获外部变量有值/地址两种方式、被延长生命周期时可能逃逸"的结论。
- 原始内容:当闭包与range同时使用时,可能出现下例中的错误……因为当前val值引用的是同一个地址的数据,所以在range循环的过程中,会不断在val地址中更新数据。而在闭包中,由于引用了外部变量val,所以在访问时会获取val地址中的值,可能会获取最后放入其中的值,而不是遍历所有值,从而导致严重的错误。修复该问题的办法是通过函数传递参数,从而避免闭包引用导致的陷阱。