若有任何问题或倡议,欢送及时交换和碰撞。我的公众号是 【脑子进煎鱼了】,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 语言、微服务架构和奇怪的零碎设计,欢送大家关注我的公众号和我进行交换和沟通。

最好的关系是相互成就,各位的点赞就是煎鱼创作的最大能源,感激反对。