"不能取"的地址和"无法调用指针方法"

时间:2017-06-14 11:22:44

标签: pointers go methods struct

编译并运作:

diff := projected.Minus(c.Origin)
dir := diff.Normalize()

这不会(产生标题中的错误):

dir := projected.Minus(c.Origin).Normalize()

有人可以帮助我理解为什么吗? (学习Go)

以下是这些方法:

// Minus subtracts another vector from this one
func (a *Vector3) Minus(b Vector3) Vector3 {
    return Vector3{a.X - b.X, a.Y - b.Y, a.Z - b.Z}
}

// Normalize makes the vector of length 1
func (a *Vector3) Normalize() Vector3 {
    d := a.Length()
    return Vector3{a.X / d, a.Y / d, a.Z / d}
}

2 个答案:

答案 0 :(得分:18)

Vector3.Normalize()方法有一个指针接收器,因此为了调用此方法,需要指向Vector3值的指针(*Vector3)。在第一个示例中,您将Vector3.Minus()的返回值存储在变量中,该变量的类型为Vector3

Go中的变量是可寻址的,当您编写diff.Normalize()时,这是一个快捷方式,编译器将自动获取diff变量的地址,以获得所需的接收器值{{{ 1}}以便拨打*Vector3。所以编译器将"转换"它

Normalize()

详见Spec: Calls:

  

如果(&diff).Normalize() x.m()的{​​{3}}包含x并且参数列表可以分配给m,则方法调用m有效。 {1}}。如果xmethod set&x方法集包含m,则x.m()(&x).m()的简写。

你的第二个例子不起作用的原因是因为函数和方法调用的返回值不可寻址,所以编译器不能在这里做同样的事情,编译器是无法获取Vector3.Minus()来电的返回值的地址。

addressable

中列出了可寻址的内容
  

操作数必须是可寻址的,即变量,指针间接或切片索引操作;或可寻址结构操作数的字段选择器;或者可寻址数组的数组索引操作。作为可寻址性要求的例外,x [在[{1}}]的表达式中也可能是(可能带括号的)Spec: Address operators:

参见相关问题:

composite literal

How to get the pointer of return value from function call?

可能"变通办法"

"最容易" (需要最少的更改)只是分配给变量,然后调用该方法。这是您的第一个解决方案。

另一种方法是修改方法以获得一个值接收器(而不是指针接收器),这样就不需要获取方法的返回值的地址,因此调用可以"链接&# 34 ;.注意,如果一个方法需要修改接收器,这可能是不可行的,因为只有当它是一个指针时才可能(因为接收器像任何其他参数一样被传递 - 通过复制 - ,如果它是'不是指针,你只能修改副本。)

另一种方法是修改返回值以返回指针(&x)而不是*Vector3。如果返回值已经是一个指针,则不需要取其地址,因为接收器对于需要指针接收器的方法来说是好的。

您也可以创建一个返回其地址的简单辅助函数。它可能看起来像这样:

Vector3

使用它:

func pv(v Vector3) *Vector3 {
    return &v
}

这也可以是dir := pv(projected.Minus(c.Origin)).Normalize() 的方法,例如:

Vector3

然后使用它:

func (v Vector3) pv() *Vector3 {
    return &v
}

有些说明:

如果您的类型仅包含3个dir := projected.Minus(c.Origin).pv().Normalize() 值,则不应发现明显的性能差异。但是你应该对你的接收器和结果类型保持一致。如果你的大多数方法都有指针接收器,那么所有方法都应该如此。如果你的大多数方法返回指针,那么所有方法都应该返回指针。

答案 1 :(得分:0)

接受的答案真的很长,所以我将发布有助于我解决的问题:

我在此行遇到此错误:

services.HashingServices{}.Hash("blabla")

所以我只是将其更改为:

(&services.HashingServices{}).Hash("blabla")