You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言defer调用fmt.Printf传入指针未生效的原因咨询

Go中defer语句的参数求值机制解析

第一个代码片段的问题原因

Go语言的defer语句有一个核心特性:当声明defer函数时,会立即对该函数的所有参数完成求值,求值结果会被保存,直到defer函数实际执行时使用。

看这段代码:

func deferRun() {
    num := 1
    numAddr := &num
    defer fmt.Printf("num is %d", *numAddr)
    num = 2
    return
}

这里defer fmt.Printf(...)中的*numAddr是fmt.Printf的第二个参数,在defer声明的瞬间,Go就会计算*numAddr的当前值(也就是1)并存储起来。后续修改num = 2只会改变num变量本身的值,但不会影响已经提前求值完成的参数。所以当函数退出、defer执行时,fmt.Printf用的是之前保存的1,输出num is 1。

第二个代码片段符合预期的原因

再看这段代码:

func deferRun() {
    num := 1
    numAddr := &num
    defer func(intAddr *int){
        fmt.Printf("num is %d", *numAddr)
    }(numAddr)
    
    num = 2
    fmt.Println("num is", *numAddr)
    return
}

这里defer的是一个匿名函数,传递给匿名函数的参数是numAddr(即num的内存地址)。按照defer的规则,声明时会立即对numAddr求值,保存的是num的地址(这个地址在函数生命周期内不会改变)。

而匿名函数内部的*numAddr是在匿名函数实际执行时才进行求值的——此时num已经被修改为2,解引用这个地址自然得到最新的2,所以输出num is 2,符合预期。

(注:这段代码里匿名函数的参数intAddr并没有被使用,直接引用了外部的numAddr,效果是一样的,因为两者指向的是同一个内存地址。)

内容的提问来源于stack exchange,提问作者Shuaike Jiang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 01:52:15