2015-12-04 194 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 
} 

但它显然是不是你想要,你需要一个结构嵌入类型别名的语法,这是不可能在,我认为你应该坚持你的第一种方法,并忽略代码冗余和丑陋的事实。