为了账号安全,请及时绑定邮箱和手机立即绑定

在 Go 中传入值或将地址传递到接口之间有什么区别?

在 Go 中传入值或将地址传递到接口之间有什么区别?

Go
qq_遁去的一_1 2022-10-04 19:27:45
假设我们有一个简单的接口和实现: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 = vabser = &v两者之间有什么区别?为什么设置顶点的地址有效?这与界面在引擎盖下的工作方式有何关系?我对Go还很陌生,所以任何帮助将不胜感激 🙏
查看完整描述

2 回答

?
翻阅古今

TA贡献1780条经验 获得超5个赞

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


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

这适用于 和 。该方法本身始终接收 的副本。v*vv


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


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

如果上述情况没有失败,则 将设置 的副本,并且效果将丢失,因为更新后的副本不会放回地图中。SetXm["a"]


回到接口:您的接口由任何实现 的类型实现。基于上面的讨论,既要实现.AbserAbs() float64Vertex*VertexAbser


假设您定义为:Vertex.Abs


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

然后,仅实现 ,因此:*VertexAbser


abser = v // This would fail

abser = &v // This would work


查看完整回答
反对 回复 2022-10-04
?
慕哥6287543

TA贡献1831条经验 获得超10个赞

首先,在Go中,一切都是按价值传递的。

指针按值传递 - 使用指针的副本。

切片按值传递 - 复制指向基础数组的指针、长度的整数值和容量的整数值。

接口也按值传递 - 使用接口值的副本。

如果你这样想,它会有所帮助。

现在,让我们关注接口:

接口值由两部分组成

  1. 指向接口表的指针

  2. 指向实际值的指针

因此,当您传递接口时,您实际上是在复制两个指针。

现在,要使类型满足接口,它需要具有接口所需的方法。如果任何方法使用指针接收器(如您的示例中所示),那么您将需要一个指向该值的指针来满足接口,这就是为什么您需要获取它的地址。func (v *Vertex) Abs() float64 {...}

假设没有一个方法需要指针接收器(比如说)。然后,您不需要指定地址,因为您只需传递它而不获取其地址。func (v Vertex) Abs() float64 {...}

我希望这能回答你的问题。


查看完整回答
反对 回复 2022-10-04
  • 2 回答
  • 0 关注
  • 75 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号