可以编译并运行:
diff := projected.Minus(c.Origin) dir := diff.Normalize()
这不会(产生标题中的错误):
dir := projected.Minus(c.Origin).Normalize()
有人可以帮我理解为什么吗?(学习围棋)
这些是这些方法:
// 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} }
该Vector3.Normalize()方法有一个 指针 接收器,因此要调用此方法,需要一个指向Vector3值的指针(*Vector3)。在第一个示例中,您将的返回值存储Vector3.Minus()在类型为的变量中Vector3。
Vector3.Normalize()
Vector3
*Vector3
Vector3.Minus()
Go中的变量是可寻址的,并且在编写时diff.Normalize(),这是一个快捷方式,编译器将自动获取diff变量的地址,以具有必需的类型的接收者值*Vector3以进行调用Normalize()。因此,编译器会将其“转换”为
diff.Normalize()
diff
Normalize()
(&diff).Normalize()
在“ 规范”中对此进行了详细说明:
x.m()如果方法集(的类型)x包含m并且参数列表可以分配给的参数列表,则该方法调用有效m。如果x是可寻址且&x方法集包含m,x.m()则为的简写(&x).m()。
x.m()
x
m
&x
(&x).m()
您的第二个示例不起作用的原因是因为函数和方法调用的返回值 不可寻址 ,因此编译器在此处无法执行同样的操作,编译器无法采用该函数的返回值的地址。Vector3.Minus()呼叫。
在“ 规范:地址”运算符中准确列出了可寻址的内容:
操作数必须是 可寻址的 ,即变量,指针间接 寻址 或切片索引操作;或可寻址结构操作数的字段选择器;或可寻址数组的数组索引操作。作为可寻址性要求的例外,x[在表达式中&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 }
然后使用它:
dir := projected.Minus(c.Origin).pv().Normalize()
一些注意事项:
如果您的类型float64仅包含3个值,则不应看到明显的性能差异。但是您应该对接收者和结果类型保持一致。如果您的大多数方法都具有指针接收器,那么所有方法都应该具有。如果您的大多数方法都返回指针,那么所有方法也都应返回。
float64