Mixins可以使用嵌入在Go(1.4.1)中实现,因为struct{}它不占用任何内存(据我所知)它适合我们想要添加某些功能的情况,或者只是将一个方法添加到一个实际上可能无关的类型与它的状态,但我们喜欢避免ParseThing(...),而是写thing.Parse(...).
所以有:
type X struct{}
func (x X) F() {
fmt.Println("functionality in X.F()")
}
type Y struct{ X }
type Z struct{ Y }
Run Code Online (Sandbox Code Playgroud)
如果我们这样做:
var z Z
z.F()
Run Code Online (Sandbox Code Playgroud)
会给我们:
functionality in X.F()
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.
现在让我们OX使用方法添加另一种类型F()并将其嵌入Z:
type Z struct {
Y
OX
}
type OX struct{} // overriding X
func (x OX) F() {
fmt.Println("functionality in OX.F()")
}
Run Code Online (Sandbox Code Playgroud)
有趣!现在我们得到了functionality in OX.F()一个向我们展示Go编译器搜索方法的方法,从自己键入,然后是最后一个嵌入类型.我们可以通过添加F()到Z:
func (x Z) F() {
fmt.Println("functionality in Z.F()")
}
Run Code Online (Sandbox Code Playgroud)
输出是functionality in Z.F().现在,如果我们删除该Z.F()方法并添加F()到Y:
//func (x Z) F() {
// fmt.Println("functionality in Z.F()")
//}
func (x Y) F() {
fmt.Println("functionality in Y.F()")
}
Run Code Online (Sandbox Code Playgroud)
然后我们看到这个错误ambiguous selector z.F; 通过指针重定向没有区别.
问题1:为什么会这样?
额外的间接水平Y意味着其他东西,但带给我的是这个.正如我猜测的那样func (t T) String() string{}是一个例外.这段代码:
type X struct{}
func (x X) String() string {
return "in X.String()"
}
type Y struct{ X }
type Z struct {
Y
OX
}
type OX struct{} // overriding X
func (x OX) String() string {
return "in OX.String()"
}
func (x Y) String() string {
return "in Y.String()"
}
Run Code Online (Sandbox Code Playgroud)
然后这个:
var z Z
fmt.Println(z)
Run Code Online (Sandbox Code Playgroud)
给我们:
{in Y.String() in OX.String()}
Run Code Online (Sandbox Code Playgroud)
这是合乎逻辑的.但是如果我们使用指针接收器:
import (
"fmt"
"testing"
)
func TestIt(t *testing.T) {
var z Z
fmt.Println(z)
}
type X struct{}
func (x *X) String() string {
return "in X.String()"
}
type Y struct{ X }
type Z struct {
Y
OX
}
type OX struct{} // overriding X
func (x *OX) String() string {
return "in OX.String()"
}
func (x *Y) String() string {
return "in Y.String()"
}
Run Code Online (Sandbox Code Playgroud)
将打印出来:
{{{}} {}}
Run Code Online (Sandbox Code Playgroud)
问题2:为什么会这样?
编译器是正确的.它应该如何决定,使用哪个OX.F和哪个Y.F应该使用?它不能.因此,您可以直接调用所需的方法:使用
z.Y.F()
Run Code Online (Sandbox Code Playgroud)
要么
z.OX.F()
Run Code Online (Sandbox Code Playgroud)
编辑:至于为什么你的榜样的工作,直到你定义F上Y,这是中提到的规格:
对于类型的值x
T或*T其中T不是指针或接口类型,x.f表示在最浅深度域或方法T,其中有这样一个f.如果没有一个f深度最浅的选择器表达式是非法的.
(重点补充.)
在定义方法之前,最浅的实现是OX.F.在你定义之后Y.F,F在同一级别上有两个s,这是非法的.
同样,编译器是正确的.您有嵌入的类型Y和OX成Z,不*Y和*OX.正如规范中所写,
设置相应的指针型的方法
*T是该组的与接收器声明的所有方法*T或T(即,它也包含的方法集T).
*T有所有方法T,但不是相反.方法套OX和Y是空的,所以很明显,fmt.Println只是打印他们,如果他们是任何其它种类的结构没有String()定义的方法.