Golang Go语言中 A Tour of Go-Pointer receivers 一点疑问

发布于 1周前 作者 h691938207 来自 Go语言

Golang Go语言中 A Tour of Go-Pointer receivers 一点疑问

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())
}


更多关于Golang Go语言中 A Tour of Go-Pointer receivers 一点疑问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

9 回复

编译器自动帮你做了你想到的步骤

更多关于Golang Go语言中 A Tour of Go-Pointer receivers 一点疑问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


为了写代码方便。否则第一个例子你得这么写(&v).Scale(10),go 默认帮你加上了取地址符,前提是变量本身是可以取地址的。
如果你写了一个签名为 func GetVertex() Vertex 的函数,GetVertex().Scale(10)就会失败,因为返回的临时变量不可取地址。

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<br>f := <a target="_blank" href="http://t.Mv" rel="nofollow noopener">t.Mv</a>; f(7) // like <a target="_blank" href="http://t.Mv" rel="nofollow noopener">t.Mv</a>(7)<br>f := <a target="_blank" href="http://pt.Mp" rel="nofollow noopener">pt.Mp</a>; f(7) // like <a target="_blank" href="http://pt.Mp" rel="nofollow noopener">pt.Mp</a>(7)<br>f := <a target="_blank" href="http://pt.Mv" rel="nofollow noopener">pt.Mv</a>; f(7) // like (*pt).Mv(7)<br>f := <a target="_blank" href="http://t.Mp" rel="nofollow noopener">t.Mp</a>; f(7) // like (&amp;t).Mp(7)<br>f := makeT().Mp // invalid: result of makeT() is not addressable<br>

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

go<br>var i interface { M(int) } = myVal<br>f := i.M; f(7) // like i.M(7)<br>

反过来就不行

package main

import (
“fmt”
“math”
)

type Vertex struct {
X, Y float64
}

func Abs(v Vertex) float64 {
return math.Sqrt(v.Xv.X + v.Yv.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

编译器自己加了。。。

你的例子错了,这个报错是说参数类型不匹配。

是,评论那个是函数(参数类型不对),不是方法(接收者类型),我搞混淆了

反过来也是可以的

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

关于你在《A Tour of Go》中提到的关于Pointer receivers(指针接收器)的疑问,我很乐意为你提供一些解答。

在Go语言中,方法接收器可以是值接收器也可以是指针接收器。选择哪种接收器取决于具体的需求。

当你需要修改接收器指向的对象时,应该使用指针接收器。因为值接收器在方法调用时会进行值拷贝,方法内对接收器的修改不会影响到原始数据。而指针接收器则直接传递对象的地址,方法内对接收器的修改会反映到原始数据上。

此外,如果接收器是一个较大的结构体,使用值接收器会导致性能下降,因为每次方法调用都会进行大量的数据拷贝。而指针接收器则避免了这个问题,因为它只是传递了对象的地址。

在编写代码时,应该根据实际需求选择合适的接收器类型。如果不需要修改接收器指向的对象,且接收器较小,那么值接收器是一个不错的选择。否则,应该使用指针接收器。

最后,需要注意的是,即使你不需要修改接收器指向的对象,但在某些情况下(如实现接口时),仍然可能需要使用指针接收器。这是因为一些接口规定了必须使用指针接收器的方法。

希望这些解答能够帮助你更好地理解Go语言中的Pointer receivers。如果你还有其他问题,欢迎随时提问。

回到顶部