Go 理解结构嵌入

Go 理解结构嵌入,go,methods,struct,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

有人能解释一下为什么这个代码打印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:)

重要的是要知道,当为类型创建另一个名称时,不能互换使用这些类型。它们是Go的typesystem的两种不同类型,尽管它们共享相同的底层表示


您有两种不同的类型,
S2
S3
S2
有一个函数
Say
S3
但是没有。但是由于
S3
S2
具有相同的底层结构,因此它确实嵌入了
S1
,它确实有一个函数
Say
,因此这就是被调用的函数。

重要的是要知道,当您为一个类型创建另一个名称时,您不能互换使用这些类型。它们是Go的typesystem的两种不同类型,尽管它们共享相同的底层表示

您有两种不同的类型,
S2
S3
S2
有一个函数
Say
S3
但是没有。但是由于
S3
S2
具有相同的底层结构,因此它确实嵌入了
S1
,它确实有一个函数
比如说
,因此这就是所调用的。

请参阅

具体来说,我们有方法集:

方法集

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

然后,结构类型:

结构类型

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

那么这个,

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

最后,这是:

调用结构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与S2不同,但它们的布局相同

该布局包括嵌入的字段,这恰好将S1.Say引入到等式中

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

struct { S1; f2 string }
struct { S1; f2 string }
还有一个叫做Say的方法

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

struct { S1; f2 string }
struct { S1; f2 string }
但是S3和S2不一样,因此S3不会从S2“继承”任何方法。相反,S3只从其底层类型继承字段/方法,即f2和S1.*(包括“Say”)。

请参阅

具体来说,我们有方法集:

方法集

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

然后,结构类型:

结构类型

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

那么这个,

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

最后,这是:

调用结构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与S2不同,但它们的布局相同

该布局包括嵌入的字段,这恰好将S1.Say引入到等式中

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

struct { S1; f2 string }
struct { S1; f2 string }
还有一个叫做Say的方法

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

struct { S1; f2 string }
struct { S1; f2 string }
但是S3和S2不一样,因此S3不“继承”