【发布时间】:2021-01-07 18:17:47
【问题描述】:
我在下面介绍两个程序:程序 1 和程序 2。
我预计程序 1 无法编译,它确实无法编译。所以这很好。
我希望程序 2 编译失败,但它成功了!这个问题是关于为什么程序 2 会成功。
程序 1
https://play.golang.org/p/qX9nY8VLlx0
package main
import (
"fmt"
"math"
)
type Abser interface {
Abs() float64
}
type Vertex struct {
X float64
Y float64
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
var a Abser
a = Vertex{3, 4}
fmt.Println(a.Abs())
}
编译失败,出现以下错误:
./prog.go:24:4: cannot use Vertex literal (type Vertex) as type Abser in assignment:
Vertex does not implement Abser (Abs method has pointer receiver)
我期待这个错误,因为*Vertex 实现了Abser,但Vertex 没有,所以我们不能将Vertex 对象分配给Abser 变量。
程序 2
https://play.golang.org/p/4bIs-fHGhYm
package main
import (
"fmt"
"math"
)
type Abser interface {
Abs() float64
}
type Vertex struct {
X float64
Y float64
}
func (v Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
var a Abser
a = &Vertex{3, 4}
fmt.Println(a.Abs())
}
这编译成功。程序的输出是:
5
为什么会成功?这里,Vertex 实现了Abser,但*Vertex 没有实现Abser。然后我如何能够将*Vertex 类型的值分配给Abser?
我需要了解哪些语言语义规则才能知道为什么会成功?
【问题讨论】:
-
为指针设置的方法包括值接收器的所有方法。为值设置的方法不包括指针接收器的方法。请参阅规范中的Method Sets。
-
@MuffinTop 我在play.golang.org/p/Kj5g6yJwI9s 的示例表明,虽然指针类型
*T的方法集包括接收器类型为*T或T的方法(这就是你所说的)。但是我看到同一个示例还表明,值类型T的方法集还包括接收器类型为*T或T的方法,因为v.AbsV()和v.AbsP()都成功了。我是否误解了结果? -
这是一个不同的属性。在可寻址值的情况下,如果方法需要指针接收器,调用会自动更改为
(&x).m()。详情请见calls。 -
参见selector expressions 中的规则#3。有several questions 和这些主题的答案。
-
“我误解了结果吗?”是的。这甚至在 Go Tour of Go (tour.golang.org/methods/6) 的中途被覆盖,因为它解释了这类问题,所以值得一读。
标签: go types interface semantics