首页 > 解决方案 > 在 Go 中传入值或将地址传入接口有什么区别?

问题描述

假设我们有一个简单的接口和实现:

type Vertex struct {
    X int
    Y int
}

type Abser interface {
    Abs() float64
}

func (v Vertex) Abs() float64 {
    sum := float64(v.X + v.Y)
    return math.Sqrt(sum)
}

现在我有一个接口变量:

var abser Abser

我想为它设置一个顶点。我可以设置一个的值,或者一个的地址:

v := Vertex{1, 1}
abser = v
abser = &v

两者有什么区别?为什么设置Vertex的地址有效?这与接口如何在幕后工作有什么关系?我对 Go 还是很陌生,所以非常感谢任何帮助

标签: arraysgopointersinterface

解决方案


在 Go 类型系统中,为 和 定义了一个使用类型值接收器T定义的方法T*T即:

func (v Vertex) Abs() float64 {...}

这适用于v*v。方法本身总是接收v.

定义为的方法*T仅定义为*T而不是为T。那是:

func (v *Vertex) SetX(newx float64) {v.X=newx}

该方法SetX仅在接收器可寻址时才有效。这是必要的,这样您就不会编写丢失数据的代码。例如:

m:=map[string]Vertex{}
m["a"]=Vertex{}
m["a"].SetX(1) // This fails! m["a"] is not addressable

如果上述情况没有失败,那么SetX会设置 的副本m["a"],并且效果会丢失,因为更新的副本没有放回地图中。

回到接口:你的Abser接口是由任何实现的类型实现的Abs() float64。基于以上讨论,两者Vertex*Vertex实现Abser.

假设您定义Vertex.Abs为:

func (v *Vertex) Abs() float64 {...}

然后,只*Vertex实现Abser,所以:

abser = v // This would fail
abser = &v // This would work

推荐阅读