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 }如果我们这样做了:
var z Z
z.F()会给我们:
functionality in X.F()到目前一切尚好。
现在,让我们使用方法F()添加另一种类型的F(),并将其嵌入到Z中
type Z struct {
Y
OX
}
type OX struct{} // overriding X
func (x OX) F() {
fmt.Println("functionality in OX.F()")
}有意思的!现在我们得到了functionality in OX.F(),它显示Go编译器搜索方法,从键入self开始,然后是最后一个嵌入式类型。我们可以通过将F()添加到Z来检查这一点
func (x Z) F() {
fmt.Println("functionality in Z.F()")
}输出为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()")
}然后我们看到这个错误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()"
}然后这个:
var z Z
fmt.Println(z)给我们:
{in Y.String() in OX.String()}这是合理的。但是如果我们使用指针接收器:
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()"
}将打印出来:
{{{}} {}}问题2:为什么会这样?
发布于 2015-02-02 16:27:32
问题1
编译器是正确的。它应该如何决定,它应该使用哪一个OX.F和Y.F?因此,直接调用所需的方法是由您自己决定的:
z.Y.F()或
z.OX.F()编辑:关于为什么您的示例在定义了Y上的F之前工作,这在特辑中有提到
对于
T或*T类型的值x,其中T不是指针或接口类型,x.f表示存在这样一个f的T中最浅的深度的字段或方法。如果没有一个深度最浅的f,则选择器表达式是非法的。
(强调后加)
在定义方法之前,最浅的实现是OX.F。在定义了Y.F之后,在同一级别上出现了两个F,这是非法的。
问题2
同样,编译器是正确的。Y和OX类型嵌入到Z中,而不是*Y和*OX。正如用特辑写的,
对应指针类型
*T的方法集是用接收方*T或T声明的所有方法集(也就是说,它还包含T的方法集)。
*T拥有T的所有方法,但不是相反的方法。OX和Y的方法集是空的,因此很明显,fmt.Println只是打印它们,就好像它们是没有定义String()方法的任何其他类型的结构一样。
发布于 2015-02-02 21:59:42
Ainar-G写出简洁的答案
规格:
对于T或*T类型的值x,其中T不是指针或接口类型,x.f表示T中存在这样一个f的最浅深度的字段或方法。如果没有一个深度最浅的f,则选择器表达式是非法的。
我想再加一点
规格:
如果S包含一个匿名字段T,则S和*S的方法集都包含对接收方T的提升方法。*S的方法集还包括带有接收器*T的提升方法。
因此,如果您只使用引用来促进方法,如
fmt.Println(&z)但这将导致选择的模糊性,因为字符串方法的可能性很小,因此由于规范的原因,选择器字符串是非法的。编译器必须抱怨,但它没有。这种行为似乎没有具体说明,只能解释为特殊情况下的普通打印操作在我的脑海中。这将如预期的那样工作。
var y Y
fmt.Println(&y)下面是工作示例游乐场
https://stackoverflow.com/questions/28281564
复制相似问题