簡體   English   中英

僅導出嵌入式結構實現的方法子集

[英]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 => bC => 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類型中有詳細說明

字段或方法 f在struct匿名場的x如果被稱為促進 xf是一個合法的選擇器 ,它表示字段或方法f

重點是促銷 ,選擇者必須合法 規范:選擇器描述了如何解析xf

以下規則適用於選擇器:

  1. 對於類型為T*T的值x ,其中T不是指針或接口類型, xf表示在T中最淺的深度處的場或方法,其中存在這樣的f 如果沒有one f具有最淺深度的one f ,則選擇器表達式是非法的。

[...]

這是什么意思? 簡單地通過嵌入, 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM