A Tour of Go-Pointer receivers 一点疑问

2019-05-13 11:48:47 +08:00
 lueffy

https://tour.golang.org/methods/4

刚开始学 go,从 A Tour of Go 开始看的,求大佬帮忙看看,非常感谢

package main

import (
	"fmt"
	"math"
)

type Vertex struct {
	X, Y float64
}

func (v Vertex) Abs() float64 {
	return math.Sqrt(v.Xv.X + v.Yv.Y)
}

func (v *Vertex) Scale(f float64) { //这里 receiver 的类型是 指针类型
	v.X = v.X * f
	v.Y = v.Y * f
}

func main() {
	v := Vertex{3, 4}
	v.Scale(10) //但是 v 是 Vertex 类型啊?为什么也能运行通过?
	fmt.Println(v.Abs())
}
package main

import (
	"fmt"
	"math"
)

type Vertex struct {
	X, Y float64
}

func (v Vertex) Abs() float64 {
	return math.Sqrt(v.Xv.X + v.Yv.Y)
}

func (v *Vertex) Scale(f float64) {
	v.X = v.X * f
	v.Y = v.Y * f
}

func main() {
	v := Vertex{3, 4}
	var m *Vertex
	m = &v //我理解的应该是这样的
	m.Scale(10)
	fmt.Println(v.Abs())
}

2238 次点击
所在节点    Go 编程语言
8 条回复
heimeil
2019-05-13 11:57:35 +08:00
编译器自动帮你做了你想到的步骤
icexin
2019-05-13 11:58:51 +08:00
为了写代码方便。否则第一个例子你得这么写(&v).Scale(10),go 默认帮你加上了取地址符,前提是变量本身是可以取地址的。
如果你写了一个签名为 func GetVertex() Vertex 的函数,GetVertex().Scale(10)就会失败,因为返回的临时变量不可取地址。
bef0rewind
2019-05-13 12:17:13 +08:00
https://golang.org/ref/spec#Method_values

As with method calls, a reference to a non-interface method with a pointer receiver using an addressable value will automatically take the address of that value: t.Mp is equivalent to (&t).Mp.

```go
f := t.Mv; f(7) // like t.Mv(7)
f := pt.Mp; f(7) // like pt.Mp(7)
f := pt.Mv; f(7) // like (*pt).Mv(7)
f := t.Mp; f(7) // like (&t).Mp(7)
f := makeT().Mp // invalid: result of makeT() is not addressable
```

Although the examples above use non-interface types, it is also legal to create a method value from a value of interface type.

```go
var i interface { M(int) } = myVal
f := i.M; f(7) // like i.M(7)
```
lueffy
2019-05-13 13:46:34 +08:00
反过来就不行

package main

import (
"fmt"
"math"
)

type Vertex struct {
X, Y float64
}

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

func Scale(v Vertex, f float64) {
v.X = v.X * f
v.Y = v.Y * f
}

func main() {
v := Vertex{3, 4}
Scale(&v, 10)
fmt.Println(Abs(v))
}

cannot use &v (type *Vertex) as type Vertex in argument to Scale
liangjf
2019-05-13 14:32:41 +08:00
编译器自己加了。。。
bef0rewind
2019-05-13 14:40:38 +08:00
@lueffy 你的例子错了,这个报错是说参数类型不匹配。
lueffy
2019-05-13 14:54:53 +08:00
@bef0rewind 是,评论那个是函数(参数类型不对),不是方法(接收者类型),我搞混淆了
liulaomo
2019-05-13 23:55:15 +08:00
@lueffy 反过来也是可以的

package main

import (
"fmt"
"math"
)

type Vertex struct {
X, Y float64
}

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

func main() {
v := Vertex{3, 4}
fmt.Println((&v).Abs())
}

因为编译器给指针类型*Vertex 隐式声明了一个同名方法。https://gfw.go101.org/article/method.html#implicit-pointer-methods

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/563577

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX