简体   繁体   English

嵌入式结构

[英]Embedded struct

Is it possible to inherit methods of a type without using embedded structs?是否可以在不使用嵌入式结构的情况下继承类型的方法?

The first snippet of code is working code that embeds the Property struct in Node and I'm able to call node.GetString that's a method on Properties .第一段代码是在Node中嵌入Property结构的工作代码,我可以调用node.GetString ,这是Properties上的一个方法。 The thing I don't like about this is when I initialize Node I have(?) to initialize the Properties struct within it.我不喜欢这个的事情是当我初始化Node我有(?)来初始化其中的Properties结构。 Is there a way around this?有没有解决的办法?

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"))
}

Ultimately, I would like to do something like the following.最终,我想做如下事情。 Where Node is of type Properties and initializing does not require initializing a Property struct too. Node的类型为Properties并且初始化也不需要初始化Property结构。 The following code doesn't work but may be clear what my goal is.以下代码不起作用,但可能很清楚我的目标是什么。

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
}

I'll be adding more structs that will use Properties 's methods which is why I'm asking.我将添加更多使用Properties方法的结构,这就是我要问的原因。 If I only had Node , I would just have methods for Node and be done.如果我只有Node ,我就会有Node方法并完成。 But because I'll have more than Node I find it kind of redundant to add the same methods to all the structs that embed Properties但是因为我将拥有的不仅仅是Node所以我发现将相同的方法添加到所有嵌入Properties的结构中是多余的

I guess more to the exact problem, I want to use Properties methods from Node without having to initialize Properties .我想更多的是确切的问题,我想使用Node Properties方法而不必初始化Properties

So you're running into an idiosyncrasy of Go here.所以你在这里遇到了 Go 的特性。 Embedding is the only way in which methods of one struct can get "promoted" to appear to exist on another struct.嵌入是一个结构体的方法可以被“提升”以出现在另一个结构体上的唯一方式。 While it feels intuitive that type Node Properties should expose the Properties methods on Node , that effect of that syntax is for Node to take on the memory layout of Properties but not any of its methods.虽然它直观的感觉是type Node Properties应该暴露Properties上的方法Node ,这句法的这种效果是Node采取的内存布局Properties ,但不是它的任何方法。

It doesn't explain why this design choice was made but the Go Spec is at least specific if dry.它没有解释为什么做出这种设计选择,但Go Spec在干燥时至少是特定的。 If you read it exactly as it appears, with no interpretation, it is very accurate:如果你完全按照它出现的方式阅读它,没有解释,它是非常准确的:

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任何其他类型 T 的方法集由所有声明为接收器类型 T 的方法组成

GetString has a receiver of type Properties not Node , seriously, interpret the spec like you're an accountant with no imagination. GetString有一个Properties类型的接收器,而不是Node ,认真地,像你是一个没有想象力的会计师一样解释规范。 With that said:照这样说:

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 xf is a legal selector that denotes that field or method f.如果 xf 是表示该字段或方法 f 的合法选择器,则结构 x 中匿名字段的字段或方法 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:给定一个结构类型 S 和一个名为 T 的类型,提升的方法包含在结构的方法集中,如下所示:

  • 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.如果 S 包含匿名字段 T,则 S 和 *S 的方法集都包含接收者 T 的提升方法。 *S 的方法集还包括接收者 *T 的提升方法。
  • If S contains an anonymous field *T, the method sets of S and *S both include promoted methods with receiver T or *T.如果 S 包含匿名字段 *T,则 S 和 *S 的方法集都包含带有接收者 T 或 *T 的提升方法。

That line about composite literals is this thing that forces you to declare Properties inside every Node you create.关于复合文字的那一行是强制您在您创建的每个Node内声明Properties东西。

ps Hi Jeff! ps嗨,杰夫!

The short answer to your last question is simply No .您最后一个问题的简短答案是No

There is a big difference between type declaration and embedding in , you can make your last example working by manually make a type conversion between Node and Properties : 类型声明和嵌入之间存在很大差异,您可以通过手动在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
}

But it's clearly that is not what you want, you want a struct embedding with a syntax of type aliasing, which is not possible in , I think that you should stuck with the your first approach and ignore the the fact the code is redundant and ugly .但很明显这不是你想要的,你想要一个带有类型别名语法的结构嵌入,这在是不可能的,我认为你应该坚持你的第一种方法并忽略代码冗余的事实并且丑陋的 。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM