2015-12-04 160 views
6

是否可以在不使用嵌入式結構的情況下繼承某種類型的方法?Golang嵌入結構

第一個代碼片段工作嵌入了Property結構中Node代碼,我能夠調用node.GetString這是上Properties的方法。我不喜歡這件事的是當我初始化Node我有(?)初始化其中的Properties結構。有沒有解決的辦法?

package main 

import "fmt" 

type Properties map[string]interface{} 

func (p Properties) GetString(key string) string { 
    return p[key].(string) 
} 

type Nodes map[string]*Node 

type Node struct { 
    *Properties 
} 

func main() { 
    allNodes := Nodes{"1": &Node{&Properties{"test": "foo"}}} // :'(
    singleNode := allNodes["1"] 
    fmt.Println(singleNode.GetString("test")) 
} 

最終,我想要做類似下面的事情。其中Node的類型爲Properties,初始化也不需要初始化Property結構。以下代碼不起作用,但可能會清楚我的目標是什麼。

package main 

import "fmt" 

type Properties map[string]interface{} 

func (p Properties) GetString(key string) string { 
    return p[key].(string) 
} 

type Nodes map[string]*Node 

type Node Properties 

func main() { 
    allNodes := Nodes{"1": &Node{"test": "foo"}} // :) 
    singleNode := allNodes["1"] 
    fmt.Println(singleNode.GetString("test")) // :D 
} 

我會補充說,將使用Properties的方法,這就是爲什麼我要求更多的結構。如果我只有Node,我只會有方法Node並完成。但是,因爲我將有超過Node我覺得那種多餘的同樣的方法添加到所有的,嵌入Properties

我想更確切的問題,我想用從NodeProperties方法,而不必在結構初始化Properties

+1

對我來說聽起來像你可能可能只是寫函數接受一個「屬性」對象的實例,並對其進行操作,而不是將它們附加到它。這是嵌入在Go中的工作方式,雖然...所以我不確定這些方法。組成,而不是繼承。 –

+0

由於某種原因,嵌入稱爲嵌入;)所有屬性字段都嵌入到節點中。 – kostya

回答

3

所以你遇到了Go的特質。嵌入是一個結構的方法可以被「提升」看起來存在於另一個結構中的唯一方法。雖然感覺直覺type Node Properties應揭露NodeProperties方法,但該語法的效果是Node採取Properties的內存佈局,但不是其任何方法。

這並不能解釋爲什麼選擇這種設計,但Go Spec至少在乾燥時是特定的。如果你完全按照它的形式閱讀它,沒有解釋,這是非常準確的:

接口類型的方法集是它的接口。任何其他類型T包含的所有方法的方法,集中聲明 與接收器類型T

GetString有一個接收器Properties類型的不Node,認真,解釋規範喜歡你,沒有想象中的會計師。這樣說:

其他規則適用於包含匿名字段的結構,如結構類型一節中所述。

...

F IN一個struct X匿名字段的字段或方法如果x.f是表示字段或方法爲f的法律選擇器稱爲促進。

升級字段的作用與結構的普通字段相似,只是它們的 不能用作結構複合字面值中的字段名稱。

給定一個結構類型S和一個名爲T型,促進了方法包括在該結構的方法集 如下:

  • 如果S包含一個匿名字段T,該方法集S和* S均爲 包括推廣方法與接收器T.方法集* S也 包括推廣方法與接收器* T。
  • 如果S包含一個匿名的 字段* T,則S和* S的方法集都包含帶有接收者T或* T的升級方法 。

該行有關複合文字是這樣的事情,迫使你申報Properties您創建的每個Node內。

p.s.嗨,傑夫!

+0

嗨,大衛!我很想知道爲什麼選擇這個設計。這可能是在規格之間的某個地方。希望你一切都好。 – Jeff

+0

@Jeff:這裏的設計選擇是Go沒有繼承,並且沒有方法重載。嵌入只是自動委派的一種方便的方法,並且具有關於選擇器如何提升字段和方法的特定規則(您始終可以直接調用它們),但沒有任何內容被「繼承」。 – JimB

1

對您最後一個問題的簡短回答只是

有類型聲明,並在嵌入,可以使你的最後一個例子通過手動工作補充NodeProperties之間的類型轉換有很大的區別:

package main 

import "fmt" 

type Properties map[string]interface{} 

func (p Properties) GetString(key string) string { 
    return p[key].(string) 
} 

type Nodes map[string]*Node 

type Node Properties 

func main() { 
    allNodes := Nodes{"1": &Node{"test": "foo"}} // :) 
    singleNode := allNodes["1"] 
    fmt.Println(Properties(*singleNode).GetString("test")) // :D 
} 

但它顯然是不是你想要,你需要一個結構嵌入類型別名的語法,這是不可能在,我認爲你應該堅持你的第一種方法,並忽略代碼冗餘和醜陋的事實。