为什么即使结构指针没有实现接口,我们也可以将结构指针分配给接口变量? [英] Why can we assign a struct pointer to an interface variable even though the struct pointer does not implement the interface?
问题描述
我在下面介绍了两个程序:程序1和程序2.
I present two programs below: program 1 and program 2.
我希望程序1无法编译,并且确实无法编译.这样很好.
I expect program 1 to fail to compile and it indeed fails to compile. So that's good.
我希望程序2无法编译,但可以成功!这个问题是关于程序2成功的原因.
I expect program 2 to fail to compile but it succeeds! This question is about why program 2 succeeds.
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())
}
无法通过此错误进行编译:
This fails to compile with this error:
./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
变量.
I was expecting this error because *Vertex
implements Abser
but Vertex
does not, so we cannot assign a Vertex
object to an Abser
variable.
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())
}
这将成功编译.该程序的输出为:
This compiles successfully. The output of the program is:
5
为什么成功?在这里,Vertex
实现Abser
,但是*Vertex
不实现Abser
.然后如何为Abser
分配类型为*Vertex
的值?
Why did this succeed? Here, Vertex
implements Abser
but *Vertex
does not implement Abser
. How am I then able to assign a value of type *Vertex
to Abser
?
要知道为什么成功,我需要了解哪些语言语义规则?
What are the language semantic rules I need to understand to know why this succeeds?
推荐答案
可分配性要求阐明接口情况下所需的内容:
The assignability requirements spell out what is needed in the case of interfaces:
值x可分配给类型T的变量("x可分配给类型" T)如果满足以下条件之一:
A value x is assignable to a variable of type T ("x is assignable to T") if one of the following conditions applies:
... T是接口类型,并且x实现T. ...
... T is an interface type and x implements T. ...
为了确定"x实现T"的规则,我们转向方法集的概念:
To determine the rules of "x implements T", we turn to the concept of method sets:
类型可能具有与之关联的方法集.方法集 接口类型是它的接口.任何其他类型T的方法集 包含以接收方类型T声明的所有方法.
A type may have a method set associated with it. The method set of an interface type is its interface. The method set of any other type T consists of all methods declared with receiver type T.
乍看之下,这意味着第一个示例中的Vertex
方法集为空,而第二个示例中的*Vertex
方法集也为空.
At first glance, this means that the method set of Vertex
in your first example is empty, and the method set of *Vertex
in your second example is also empty.
但是,规范会继续指定:
However, the spec goes on to specify:
对应的指针类型* T的方法集是全部的集合 用接收者* T或T声明的方法(也就是说,它还包含 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).
这意味着方法集*Vertex
自动包含Vertex
的方法集,而不是相反的方法.
This means that the method set of *Vertex
automatically includes the method set of Vertex
, but not the other way around.
这在您的第一个示例中无济于事,但是在第二个示例中,Vertex
的方法集确实包含了Abs() float64
.由于这是实现Abser
接口所需的全部,因此*Vertex
被视为实现Abser
.
This does not help in your first example, but in the second example the method set of Vertex
does include Abs() float64
. Since this is all that is required to implement the Abser
interface, *Vertex
is deemed to implement Abser
.
这篇关于为什么即使结构指针没有实现接口,我们也可以将结构指针分配给接口变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!