【问题标题】:Embedded struct嵌入式结构
【发布时间】:2015-12-04 01:34:22
【问题描述】:

是否可以在不使用嵌入式结构的情况下继承某个类型的方法?

代码的第一个 sn-p 是在 Node 中嵌入 Property 结构的工作代码,我可以调用 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"))
}

最终,我想做类似以下的事情。其中NodeProperties 类型,并且初始化也不需要初始化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

【问题讨论】:

  • 在我看来,您可能只需要编写函数来接受Properties 对象的实例并对其进行操作,而不是将它们附加到它上面。这就是嵌入 Go 中的工作原理......所以我不确定是否有解决方法。组合,而不是继承。
  • 嵌入被称为嵌入是有原因的;)所有属性字段都嵌入到节点中。

标签: go


【解决方案1】:

所以你在这里遇到了 Go 的特质。嵌入是一个结构的方法可以被“提升”以出现在另一个结构上的唯一方法。虽然感觉很直观 type Node Properties 应该在 Node 上公开 Properties 方法,但该语法的效果是 Node 采用 Properties 的内存布局,但不是它的任何方法。

它没有解释为什么做出这种设计选择,但Go Spec 至少是干的。如果您完全按照它的外观阅读它,没有任何解释,那么它是非常准确的:

接口类型的方法集就是它的接口。任何其他类型 T 的方法集由声明的所有方法组成 接收器类型为 T

GetString 有一个类型为Properties 而不是Node 的接收器,认真地解释规格,就像你是一个没有想象力的会计师一样。话虽如此:

更多规则适用于包含匿名字段的结构,如结构类型部分所述。

...

如果 x.f 是表示该字段或方法 f 的合法选择器,则称为提升结构 x 中匿名字段的字段或方法 f。

Promoted 字段的行为类似于结构的普通字段,除了它们 不能用作结构的复合文字中的字段名称。

给定一个结构类型 S 和一个名为 T 的类型,提升的方法是 包含在struct的方法集中如下:

  • 如果 S 包含匿名字段 T,则 S 和 *S 的方法集都 包括带有接收器 T 的提升方法。*S 的方法集也 包括带有接收器 *T 的提升方法。
  • 如果 S 包含匿名 字段 *T,S 和 *S 的方法集都包含提升的方法 与接收器 T 或 *T。

关于复合字面量的那一行是强制你在你创建的每个 Node 中声明 Properties 的东西。

附言嗨杰夫!

【讨论】:

  • 嗨大卫!我很想知道为什么做出这样的设计选择。它可能在规范中的某个地方,就在两行之间。希望你一切都好。
  • @Jeff:这里的设计选择是 Go 没有继承,也没有方法重载。嵌入只是一种方便的自动委托方法,有关于选择器如何提升字段和方法的特定规则(您也可以随时直接调用它们),没有什么是“继承”的。
【解决方案2】:

您最后一个问题的简短回答是

中的类型声明和嵌入有很大区别,您可以通过手动在 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
}

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-12-23
    • 1970-01-01
    • 1970-01-01
    • 2017-12-24
    • 1970-01-01
    • 1970-01-01
    • 2014-08-11
    相关资源
    最近更新 更多