Dom*_* M. 3 methods struct embedding go
是否可以只导出嵌入式结构实现的方法的子集?这是一种非常不同的方法来减少代码的复制和粘贴,还有一种更惯用的方法吗?
type A struct {
}
func (a *A) Hello() {
fmt.Println("Hello!")
}
func (a *A) World() {
fmt.Println("World!")
}
type B struct {
A
}
type C struct {
A
}
func main() {
b := B{}
c := C{}
// B should only export the Hello - function
b.Hello()
// C should export both Hello - and World - function
c.Hello()
c.World()
}
Run Code Online (Sandbox Code Playgroud)
这就是嵌入工作的方式,你无能为力.(实际上有,最后看到肮脏的伎俩.)
您可以通过接口实现您想要的功能.使你的结构取消导出,(B=> b和C=> c),并创建像构造函数一样的函数,它返回接口类型,只包含你想要发布的方法:
type b struct {
A
}
type c struct {
A
}
type Helloer interface {
Hello()
}
type HelloWorlder interface {
Helloer
World()
}
func NewB() Helloer {
return &b{}
}
func NewC() HelloWorlder {
return &c{}
}
Run Code Online (Sandbox Code Playgroud)
您可能希望将接口和函数称为不同,这仅用于演示.
另请注意,虽然返回的Helloer接口不包含该World()方法,但仍然可以使用类型断言 "到达"它,例如:
h := NewB() // h is of type Helloer
if hw, ok := h.(HelloWorlder); ok {
hw.World() // This will succeed with the above implementations
}
Run Code Online (Sandbox Code Playgroud)
在Go Playground尝试这个.
如果类型嵌入了类型A,则A获得提升的(fields和)方法将成为嵌入器类型的方法集的一部分(因此成为类型的方法A).这在Spec:Struct类型中有详细说明:
重点是促销,选择者必须合法.规范:选择器描述如何x.f解决:
以下规则适用于选择器:
- 对于值
x类型的T或*T其中T不是指针或接口类型,x.f表示在最浅深度域或方法T,其中有这样一个f.如果没有确切的one f深度,则选择器表达式是非法的.[...]
这是什么意思?简单地通过嵌入,B.World将表示B.A.World方法,即在最浅的深度.但是如果我们能够实现那样B.A.World不会是最浅的,那么类型B将不会有这种World()方法,因为B.A.World不会得到提升.
我们怎样才能做到这一点?我们可以添加一个名称为的字段World:
type B struct {
A
World int
}
Run Code Online (Sandbox Code Playgroud)
这种B类型(或更确切地说*B)不具有World()方法,因为B.World表示该字段而不是B.A.World前者处于最浅深度.在Go Playground尝试这个.
同样,这并不妨碍任何人明确引用B.A.World(),因此可以"到达"并调用该方法,我们所实现的只是类型B或*B没有World()方法.
这个"肮脏技巧"的另一个变种是利用第一条规则的结尾:"如果没有一条 f最浅的深度".这可以实现为嵌入另一种类型,另一种也具有World字段或方法的结构,例如:
type hideWorld struct{ World int }
type B struct {
A
hideWorld
}
Run Code Online (Sandbox Code Playgroud)
在Go Playground上试试这个变种.