6.4. 嵌入结构体
在声明结构体类型时,如果某个成员的类型是结构体,但省略该成员的名称,这种用法被称为嵌入结构体,例如下面代码中,结构体 Sc
中嵌入了 Sp
成员:
type Sp struct {
x: i32
}
type Sc struct {
Sp // 嵌入结构体
y: i32
}
嵌入结构体的成员名称就是其类型名称,我们依然可以使用选择符 .
访问它,例如下面的打印代码:
v: Sc
println(v.Sp.x)
在这个例子中,甚至可以省略 .Sp
的部分,比如上面的代码跟下述代码是等价的:
v: Sc
println(v.x)
在这种用法中,结构体 Sp
看起来似乎被嵌到结构体 Sc
中去了,这也是嵌入结构体名称的来源。但是如果结构体中包含了和被嵌结构体同样名称的成员,则访问被嵌结构体同名成员时不能进行省略,例如:
// 版权 @2023 凹语言 作者。保留所有权利。
type Sp struct {
x: i32
}
type Sc2 strct {
Sp
x: f32
}
func main(){
v: Sc2
println(v.x) // 打印的是Sc2.x,f32类型
println(v.Sp.x) // 打印的是Sc2.Sp.x,i32类型
}
嵌入结构体除了可以复用类型的数据布局,另一个重要的功能是它可以复用类型方法,结构体会自动拥有被嵌入类型的方法,例如:
// 版权 @2023 凹语言 作者。保留所有权利。
type Sp struct {
x: i32
}
func Sp.Show {
println(this.x)
}
type Sc struct {
Sp
y: i32
}
func main {
v := Sc{Sp:Sp{x: 42}, y: 13}
v.Show() // 42
}
在声明嵌入结构体字面量时,不能省略被嵌入结构体名,比如上例中的
Sc{Sp:Sp{x: 42}, y: 13}
,如果省略为{x: 42, y: 13}
将被视为非法。
Sc
中 嵌入 Sp
后,获得了后者的方法,使得 Sc
类型的变量 v
可以执行 Show
操作;在该例中,v.Show()
等价于 v.Sp.Show()
。如果结构体拥有和被嵌结构体同样名称的方法,处理方法与同名成员类似,例如:
// 版权 @2023 凹语言 作者。保留所有权利。
type Sp struct {
x: i32
}
func Sp.Show {
println(this.x)
}
type Sc struct {
Sp
x: f32
}
func Sc.Show {
println(this.x)
}
func main {
v := Sc{Sp:Sp{x: 42}, x: 13.14}
v.Show() // 13.14
v.Sp.Show() // 42
}
为了实现对象复用,凹语言没有采用继承的设计(这与C++不同),而是使用了组合的设计。嵌入结构体就是组合的具体表现,嵌入结构体复用了被嵌入类型的内存布局和方法集,与接口(将在第7章介绍)一起,构成了凹语言对象抽象、复用的基础。