我对以下程序的实验感到困惑,该程序涉及使用结构嵌入实现接口,分别使用命名类型和指针接收器:
package main
import "fmt"
type MyInt interface {
mytest()
}
type Base struct {
}
func (b *Base) mytest() {
fmt.Println("From base")
}
type Derived struct {
Base
}
type Derived2 struct {
*Base
}
func main() {
// Only this one has problem
// However, if we change mytest's receiver from *Base to Base, all the four assignments are OK
var _ MyInt = Derived{}
// OK
var _ MyInt = &Derived{}
var _ MyInt = Derived2{}
var _ MyInt = &Derived2{}
}
请参阅代码中的注释以了解我的困惑。是否有任何主要方法来解释它们?
答案 0 :(得分:1)
给定结构类型S和名为T的类型,提升的方法是 包含在结构的方法集中,如下所示:
- 如果S包含匿名字段T,则方法设置为S和* S. 包括与接收者T的推广方法。
- * S的方法集也 包括带接收器* T的推广方法。
- 如果S包含匿名 field * T,S和* S的方法集都包括提升方法 接收器T或* T。
在您的代码中不起作用的情况:
var _ MyInt = Derived{}
此处Derived
的方法集(包含匿名字段Base
)包含规则1的Base
方法。因为mytest
是{{1}的方法而不是*Base
,它被提升为Base
(第二条规则)的方法,而不是*Derived
的方法。
为什么会那样?嗯,它类似于结构方法集的规则:Derived
的方法也是T
的方法,但反之亦然。这是因为指针接收器的方法可以期望能够改变其接收器,但是非指针接收器的方法可能不会。
答案 1 :(得分:0)
根据你的代码函数,mytest可以在接收器上调用,指针指向Base。
Struct Derived继承/嵌入Base和Derived2继承/嵌入* Base,即指向base的指针。
对于
var _MyInt =& Derived2 {}:这里创建Derived2的指针,因为Dervied2继承自* Base,_MyInt调用mytest将起作用
var _MyInt = Derived2 {}:Derived2的实例已创建,因为Dervied2继承自* Base,_MyInt调用mytest将起作用
var _MyInt =& Derived {}:这里创建了Derived的指针,因为Dervied继承自Base调用_MyInt上的mytest将起作用
var _MyInt = Derived {}:Derived的实例已创建,并且由于Dervied继承自Base调用mytest on _MyInt将无法使用指向Base的指针。
你正确地指出将接收器从* Base更改为Base将起作用,因为Go将能够从指针识别Object并且能够调用mytest。
根据golang规范 类型可以具有与其关联的方法集。接口类型的方法集是其接口。任何其他类型T的方法集由用接收器类型T声明的所有方法组成。相应指针类型* T的方法集是用receiver * T或T声明的所有方法的集合(也就是说,它还包含方法一套T)。
希望这有帮助