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

代码的第一段是在Node中嵌入Property结构的工作代码,我可以调用node.GetString,这是Properties上的一种方法。我不喜欢这样的事情是当我初始化Node时,我具有(?)来初始化其中的Properties结构。有没有解决的办法?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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结构。以下代码不起作用,但可能清楚我的目标是什么。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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的结构添加相同的方法有点多余

我想确切的问题更多,我想使用Node中的Properties方法而不必初始化Properties

  • 在我看来,您也许可以编写接受Properties对象实例并对其进行操作的函数,而不是将其附加到该函数。 不过,这就是嵌入Go的工作方式,因此我不确定是否有解决办法。 组成,而不是继承。
  • 嵌入由于某种原因被称为嵌入;)所有属性字段都嵌入到Node中。

因此,您在这里遇到了Go的特质。嵌入是一个结构中的方法可以"提升"以似乎存在于另一个结构中的唯一方法。尽管在type Node Properties上应该公开Node上的Properties方法是很直观的,但该语法的作用是使Node承担Properties的内存布局,而不是其任何方法。

它没有解释为什么选择这种设计,但是Go Spec至少是特定的(如果干燥的话)。如果您完全按原样阅读它,没有任何解释,那么它是非常准确的:

The method set of an interface type is its interface. The method set of any other type T consists of all methods declared
with receiver type T

GetString的接收器类型为Properties而不是Node,认真地,将规范解释为您是没有想象力的会计师。照这样说:

Further rules apply to structs containing anonymous fields, as described in the section on struct types.

...

A field or method f of an anonymous field in a struct x is called promoted if x.f is a legal selector that denotes that field or method f.

Promoted fields act like ordinary fields of a struct except that they
cannot be used as field names in composite literals of the struct.

Given a struct type S and a type named T, promoted methods are
included in the method set of the struct as follows:

  • If S contains an anonymous field T, the method sets of S and *S both
    include promoted methods with receiver T. The method set of *S also
    includes promoted methods with receiver *T.
  • If S contains an anonymous
    field *T, the method sets of S and *S both include promoted methods
    with receiver T or *T.

关于复合文字的这一行迫使您在创建的每个Node中声明Properties

ps。嗨,杰夫!

  • 嗨,大卫! 我想听听为什么要做出这种设计选择。 它可能在规格书中就在线条之间的深处。 希望你一切都好。
  • @Jeff:这里的设计选择是Go没有继承,也没有方法重载。 嵌入只是自动委派的一种便捷方法,它具有关于选择器如何提升字段和方法的特定规则(您也可以始终直接调用它们),没有"被继承"的东西。

您最后一个问题的简短答案就是"否"。

类型声明和在golang中嵌入之间有很大的区别,您可以通过在NodeProperties之间手动进行类型转换来使最后一个示例正常工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
}

但是很明显,这不是您想要的,您想要的是使用类型别名的语法嵌入结构,这在golang中是不可能的,我认为您应该坚持第一种方法,而忽略代码是多余的事实,并且丑陋 。