有趣的defer

UYAD · 2019-02-12 13:50:31 · 1647 次点击 · 预计阅读时间不到 1 分钟 · 大约8小时之前 开始浏览    
这是一个创建于 2019-02-12 13:50:31 的文章,其中的信息可能已经有所发展或是发生改变。

package main

import "fmt"

func main() {
	message := "消息1"
	defer func() {
		fmt.Println("第一个defer:", message)
	}()
	message = "消息改变了"
	defer func(m string) {
		fmt.Println("第二个defer:", m)
		message = "消息又改变了"
	}(message)
	message = "消息2"
}

有趣的defer,试着注释其中某些行,猜猜最终输出的是什么。


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1647 次点击  ∙  1 赞  
加入收藏 微博
6 回复  |  直到 2019-06-03 20:26:11
alha
alha · #1 · 6年之前

第二个defer:消息改变了 第一个defer:消息2

Cynthia
Cynthia · #2 · 6年之前

运行结果如下: 第二个defer: 消息改变了 第一个defer: 消息又改变了

不明白为什么不是: 第二个defer: 消息2 第一个defer: 消息又改变了

UYAD
UYAD · #3 · 6年之前
CynthiaCynthia #2 回复

运行结果如下: 第二个defer: 消息改变了 第一个defer: 消息又改变了 不明白为什么不是: 第二个defer: 消息2 第一个defer: 消息又改变了

加断点调试会清楚些

chenjiandongx
chenjiandongx · #4 · 6年之前

个人的一点见解

package main

import "fmt"

func main() {
    message := "消息1"
    defer func() {
        fmt.Println("第一个defer:", message)
    }()
    message = "消息改变了"
    defer func(m string) {
        fmt.Println("第二个defer:", m)
        message = "消息又改变了"
    }(message)
    message = "消息2"
}

在上面的中,这部分应该是一个 代码块

message = "消息改变了"
defer func(m string) {
    fmt.Println("第二个defer:", m)
    message = "消息又改变了"
}(message)

也就是说你在声明 defer 函数的时候,参数已经被复制并传入到函数中,这时候 message 已经是确定的,它已经不是你全局持有的 message 变量了。

怎么验证呢,你可以传递字符串指针进去。

func main() {
    message := new(string)
    *message = "消息改变了"
    defer func(m *string) {
        fmt.Println("第二个defer:", *m)
    }(message)
    *message = "消息2"
}

因为指针只是保留的引用,存储着字符串的内存地址,所以它的状态会是一致的。代码会输出

第二个defer: 消息2
humm0214
humm0214 · #5 · 6年之前

1、函数的参数是值传递 2、defer执行 按照先进后出

yuzhiquan
yuzhiquan · #6 · 6年之前

第二个defer是传入的时候就确定了的,第一个defer是闭包

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传