若有任何问题或倡议,欢送及时交换和碰撞。我的公众号是 【脑子进煎鱼了】,GitHub 地址:https://github.com/eddycjy。
大家好,我是煎鱼。
前几天在读者交换群里看到一位小伙伴,在向大家征询 Go 相干的技术问题。
疑难是:“各位大佬,我在学习 defer 遇到闭包的时候很懵逼,谁比拟明确,能指导?”
疑难
他的疑难是上面这道 Go 语言的 defer 题目,大家一起看看:
func main() { var whatever [6]struct{} for i := range whatever { defer func() { fmt.Println(i) }() }}
请本人先想一下输入的后果答案是什么。
这位小伙伴按本人的了解后,认为该当输入 xx。但最终的输入后果,可能与其思考的有所偏差,一时想不通。
解惑
这段程序的输入后果是:
555555
为什么全是 5,为什么不是 0, 1, 2, 3, 4, 5 这样的输入后果呢?
其根本原因是闭包所导致的,有两点起因:
- 在
for
循环完结后,局部变量i
的值曾经是 5 了,并且defer
的闭包是间接援用变量的 i。 - 联合
defer
关键字的个性,可得悉会在main
办法主体完结后再执行。
联合上述,最终输入的后果是曾经自增结束的 5。
进一步思考
既然理解了为什么,咱们再变形一下。再看看另外一种状况,代码如下:
func main() { var whatever [6]struct{} for i := range whatever { defer func(i int) { fmt.Println(i) }(i) }}
与第一个案例不同,咱们这回把变量 i
传了进去。那么他的输入后果是什么呢?
这段程序的输入后果是:
543210
为什么是 5, 4, 3, 2, 1, 0 呢,为什么不是 0, 1, 2, 3, 4, 5?(难道煎鱼敲错了吗?)
其根本原因在于两点:
- 在
for
循环时,局部变量i
曾经传入进defer func
中 ,属于值传递。其值在defer
语句申明时的时候就曾经确定下来了。 - 联合
defer
关键字的个性,是按先进后出的程序来执行的。
联合上述,最终输入的后果是 5, 4, 3, 2, 1, 0。
下一个疑难
没过一会,这位小伙伴又有了新的感悟。抛出了新的示例问题,如下:
func f1() (r int) { defer func() { r++ }() return 0}func f2() (r int) { t := 5 defer func() { t = t + 5 }() return t}func f3() (r int) { defer func(r int) { r = r + 5 }(r) return 1}
主函数:
func main() { println(f1()) println(f2()) println(f3())}
请本人先想一下输入的后果答案是什么。
这段程序的输入后果是:
151
为什么是 1, 5, 1 呢,而不是 0, 10, 5,又或是其余答案?
欢送大家在下方评论区留言探讨和分享解题的思路,一起思考和提高。
我的公众号
分享 Go 语言、微服务架构和奇怪的零碎设计,欢送大家关注我的公众号和我进行交换和沟通。
最好的关系是相互成就,各位的点赞就是煎鱼创作的最大能源,感激反对。