我正在经历围棋之旅。我了解到,如果我们有一个接受指针作为接收器的方法,它也会接受一个值类型作为接收器(go 会自动进行转换)。
type Vertex struct { X, Y float64 }
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X * v.X + v.Y * v.Y)
}
那么下面的代码是有效的,无论是通过值还是指针接收Vertexv := Vertex{1, 2}
fmt.Println(v.Abs())
p := &v
fmt.Println(p.Abs())
但是,假设我们有以下接口(interface):type Abser interface {
Abs() float64
}
那么,为什么下面的代码无效呢?var a Abser
v := Vertex{1, 2}
a = v // invalid
我的理解是这样就可以了。即使 v 是一个值类型,它“实现”了接受指针接收器的 Abs 函数,它也会按值接受它吗?接口(interface)是否只是为了更严格地定义接口(interface)变量可以在右侧保存的内容而设计?该接口(interface)将 *Vertex 和 Vertex 视为两种不同的类型,但是 Abs() 方法也没有问题处理。
最佳答案
在这两种情况下,Go 都需要一个指针来运行该方法。最大的不同是方法调用会自动取v
的地址。 ,但检查某物是否实现了接口(interface)并没有。
方法调用:
在普通类型上调用带有指针接收器的方法时,如果允许,Go 将自动获取地址。来自 spec on method calls (重点是我的):
A method call x.m() is valid if the method set of (the type of) x contains m and the argument list can be assigned to the parameter list of m. If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m()
在这种情况下,
x
指您的变量 v
并且是 addressable .所以在方法调用时,Go 会自动运行 (&v).Abs()
.任务:
当试图 assign
a = v
,必须填写的支票是T is an interface type and x implements T.
. v
实现 Abser
仅当它的 method set匹配界面。该方法集确定如下:The method set of any other type T consists of all methods declared with receiver type T. The method set of the corresponding pointer type *T is the set of all methods declared with receiver *T or T (that is, it also contains the method set of T).
你会注意到,在计算方法集时,Go 并没有采用
v
的地址。就像在方法调用中所做的那样。 这意味着为 var v Vertex
设置的方法为空,未能实现接口(interface)。 解决方案:
解决这个问题的方法是获取
v
的地址你自己:var a Abser
v := Vertex{1, 2}
a = &v
通过这样做,您现在正在查看 *Vertex
的方法集其中包括Abs() float64
从而实现接口(interface)Abser
.
关于go - 为什么接口(interface)分配比方法调用更严格?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63498619/