了解struct embedding

时间:2017-08-26 19:33:09

标签: go methods struct

有人可以解释一下为什么这段代码打印1而不是2?

package main

import (
    "fmt"
)

type S1 struct{
    f1 string
}

type S2 struct{
    S1
    f2 string
}   

func (s *S1) Say(){
    fmt.Println("1")
}   

func (s *S2) Say(){
    fmt.Println("2")
}       

type S3 S2

func main() {
    var s3 S3
    s3.Say()
}

(Runnable at:https://play.golang.org/p/_cjNxBKgSf

2 个答案:

答案 0 :(得分:6)

请参阅this answer

具体来说,从the Go spec我们有方法集:

  

方法集

     

类型可能具有与之关联的方法集。方法集   接口类型是它的接口。任何其他类型T的方法集   由接收器类型T声明的所有方法组成。方法集   对应的指针类型* T是所有方法的集合   用接收器* T或T声明(也就是说,它也包含方法   一套T)。进一步的规则适用于包含嵌入字段的结构,   如结构类型一节中所述。任何其他类型都有   空方法集。在方法集中,每个方法必须具有唯一性   非空方法名称。

然后结构类型:

  

结构类型

     

结构是一系列命名元素,称为字段,每个元素   有一个名字和类型。可以明确指定字段名称   (IdentifierList)或隐式(EmbeddedField)。在结构中,   非空白字段名称必须是唯一的。

然后这个:

  

使用类型但没有显式字段名称声明的字段称为嵌入字段。

最后,这个:

  

调用struct x中嵌入字段的字段或方法f   如果x.f是表示该字段或方法f的合法选择器,则提升

     

提升字段的作用类似于结构的普通字段,但它们除外   不能在结构的复合文字中用作字段名称。

     

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

If S contains an embedded 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 embedded field *T, the method sets of S and *S 
both include promoted methods with receiver T or *T.

如何将所有这些结合起来?

你有

type S2 struct{
    S1
    f2 string
}

使S1成为嵌入字段,并使S1.Say可见。

然后你有:

type S3 S2

这使得S3具有与S2相同的内存布局和字段,但不会创建类型等价。这并不是说S3“是一个”S2,而是S3 不一样,但是它们确实具有相同的布局。

该布局包括嵌入字段,恰好将S1.Say引入等式。

换句话说,类型S2的基础类型为:

struct { S1; f2 string }

和一个名为Say。

的方法

类型S3具有相同的基础类型:

struct { S1; f2 string }

但S3和S2不一样,因此S3不会“继承”来自S2的任何方法。相反,S3仅从其基础类型继承字段/方法,即f2和S1。*(包括“Say”)。

答案 1 :(得分:2)

重要的是要知道,当您为类型创建另一个名称时,无法交替使用这些类型。它们是Go的类型系统的两个不同类型,即使它们共享相同的底层表示。

您有两种不同的类型,S2S3S2有一个函数SayS3但是没有。但由于S3S2具有相同的基础结构,因此 嵌入了S1,其中 具有函数{ {1}},这就是所谓的。