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()
定义的方法.