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

Go语言中向接口传递值与传递地址的区别是什么?

Go接口两种赋值方式的区别与底层原理

1. 两种赋值的核心差异

  • 执行abser = v时,接口变量存储的是Vertex实例的值拷贝,后续修改原始变量v的X/Y字段,接口内的副本不会同步变更,调用Abs()返回的是旧值的计算结果。
  • 执行abser = &v时,接口变量存储的是Vertex实例的指针拷贝,后续修改原始变量v的字段,接口内的指针指向同一块内存地址,调用Abs()会返回最新值的计算结果。

可以参考如下测试代码直观感受差异:

v := Vertex{1, 1}
abser = v
v.X = 100
fmt.Println(abser.Abs()) // 输出√(1+1)≈1.414,读取的是旧副本
abser = &v
fmt.Println(abser.Abs()) // 输出√(100+1)≈10.05,读取的是修改后的原始变量

2. 指针类型赋值合法的原因

这是Go语言为方法调用提供的自动解引用语法糖机制:
当你为值类型Vertex实现了Abs()方法后,Go会自动为对应的指针类型*Vertex生成隐式的Abs()方法,调用时会自动解引用指针拿到底层的Vertex值,执行你定义的方法逻辑。因此*Vertex也天然满足Abser接口的实现要求,赋值合法。

注意该规则反向不成立:如果你是为*Vertex指针类型实现了Abs()方法,那么只有指针类型满足接口要求,值类型Vertex不会自动生成对应方法,直接赋值abser = v会编译报错,避免修改副本产生不符合预期的行为。

3. 与接口底层实现的关联

Go的非空接口底层是名为iface的结构体,包含两个核心指针:

  • tab指针:指向itab表,存储接口类型信息、实际赋值的具体类型信息、以及具体类型对应接口方法的实现地址
  • data指针:指向实际动态值的内存地址
    两种赋值方式的底层差异直接体现在这两个指针上:
  • 赋值值类型v时,itab中存储的具体类型为Vertex,data指针指向堆上分配的Vertex值副本的地址
  • 赋值指针类型&v时,itab中存储的具体类型为*Vertex,data指针指向原始变量v的内存地址
    调用abser.Abs()时,Go会先从itab中找到对应类型的Abs()方法实现,再把data指针指向的内容作为接收者传入方法,因此两种场景都能正常执行逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 13:24:04