![](/img/trans.png)
[英]How GoLang's typecast to interface implemented by a struct and embedded struct works
[英]Export only subset of methods implemented by embedded struct
是否可以只導出嵌入式結構實現的方法的子集? 這是一種非常不同的方法來減少代碼的復制和粘貼,還有一種更慣用的方法嗎?
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()
}
這就是嵌入工作的方式,你無能為力。 (實際上有,最后看到骯臟的伎倆。)
您可以通過接口實現您想要的功能。 使你的結構取消導出,( 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{}
}
您可能希望將接口和函數稱為不同,這僅用於演示。
另請注意,雖然返回的Helloer
接口不包含World()
方法,但仍然可以使用類型斷言 “到達”它,例如:
h := NewB() // h is of type Helloer
if hw, ok := h.(HelloWorlder); ok {
hw.World() // This will succeed with the above implementations
}
在Go Playground嘗試這個。
如果類型嵌入類型A
,則提升的A
(字段和)方法將成為嵌入器類型的方法集的一部分(因此成為類型A
方法)。 這在Spec:Struct類型中有詳細說明:
重點是促銷 ,選擇者必須合法 。 規范:選擇器描述了如何解析xf
:
以下規則適用於選擇器:
[...]
這是什么意思? 簡單地通過嵌入, B.World
將表示BAWorld
方法,因為它是在最淺的深度。 但是如果我們能夠實現 BAWorld
不會是最淺的,那么B
就不會有這種World()
方法,因為BAWorld
不會被提升。
我們怎樣才能做到這一點? 我們可能會添加一個名為World
的字段:
type B struct {
A
World int
}
這個B
類型(或者更確切地說是*B
)將沒有World()
方法,因為B.World
表示字段而不是BAWorld
因為前者處於最淺的深度。 在Go Playground嘗試這個。
同樣,這並不妨礙任何人明確地引用BAWorld()
,因此可以“到達”並調用該方法,我們所獲得的只是類型B
或*B
沒有World()
方法。
這個“骯臟技巧”的另一個變體是利用第一條規則的結尾: “如果沒有一個具有最淺深度的f
” 。 這可以實現以嵌入另一種類型,另一種也具有World
字段或方法的結構,例如:
type hideWorld struct{ World int }
type B struct {
A
hideWorld
}
在Go Playground上試試這個變種。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.