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

为何添加fmt.Printf会改变Go中持有空结构体的接口变量相等性结果?

为什么fmt.Printf会影响Go语言接口的比较结果?

环境

go version go1.25.6 darwin/amd64

带fmt.Printf的测试代码

package main

import "fmt"

type Animal interface {
    Name() string
}

type Cat struct {
}

func (c Cat) Name() string {
    return "cat"
}

func main() {
    var c1 Animal = new(Cat)
    var c2 Animal = new(Cat)

    fmt.Println(c1 == c2)
    fmt.Printf("%p,%p", c1, c2)
}

输出

true
0x56d83c0,0x56d83c0

注释fmt.Printf后的测试代码

package main

import "fmt"

type Animal interface {
    Name() string
}

type Cat struct {
}

func (c Cat) Name() string {
    return "cat"
}

func main() {
    var c1 Animal = new(Cat)
    var c2 Animal = new(Cat)

    fmt.Println(c1 == c2)
    // fmt.Printf("%p,%p", c1, c2)
}

输出

false

原因解析

这是Go语言编译器的逃逸分析和接口值结构共同作用的结果。

Go的接口值包含两部分:类型指针和数据指针。只有当两个接口值的类型指针和数据指针完全相等时,比较结果才为true。

  • 当代码中存在fmt.Printf("%p", c1)时,%p格式化符会读取接口的底层数据指针,这会触发编译器将new(Cat)创建的Cat实例分配到堆上。为了优化,编译器会复用两次new(Cat)的堆内存地址,导致c1和c2的底层数据指针完全相同,接口比较结果为true。
  • 注释掉fmt.Printf后,编译器的逃逸分析判断Cat实例不需要逃逸到堆上,会将它们分配到栈上。栈上两次new(Cat)会生成两个独立的内存地址,此时c1和c2的底层数据指针不同,接口比较结果自然为false。

简单来说:打印操作强制让实例逃到堆上并被复用,不打印时实例在栈上独立分配,导致接口数据指针不同,最终让比较结果反转。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.11 10:04:51