go语言struct中的匿名字段与组合

很多文档中都反复强调了, go语言中没有继承, 只有组合, 活用组合的特性可以让代码更加优雅. 在go语言中, struct中的匿名字段实现了组合的特性

struct匿名字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
type boy struct {
}

func (b boy) eat() {
fmt.Println("The boy is eating an apple")
}

type girl struct {
}

func (g girl) eat() {
fmt.Println("The girl is eating an orange")
}

type human struct {
b boy
girl // 匿名字段 接口体重只写了数据类型的字段叫匿名字段
}

组合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import "fmt"

type boy struct {
}

func (b boy) eat() {
fmt.Println("The boy is eating an apple")
}

type girl struct {
}

func (g girl) eat() {
fmt.Println("The girl is eating an orange")
}

type human struct {
b boy
girl // 匿名字段
}

func main() {
var h human
h.b.eat()
h.girl.eat()
h.eat()
}

执行结果:

1
2
3
The boy is eating an apple
The girl is eating an orange
The girl is eating an orange

h.b.eat() 的运行结果 The boy is eating an apple 是符合我们的预期的.

h.girl.eat() 的运行结果 The girl is eating an orange 也符合预期, 只不过因为girl匿名字段, 没有字段名称, 所以这里可以使用数据类型来调用其内部的eat函数

h.eat() 这个函数调用比较奇怪, 正常情况下, 应该是定义在human下的eat方法才能被我们直接调用, 但是这里, 在human没有直接定义eat方法的情况下, eat函数依然被执行成功, 而且输出的结果与h.girl.eat()的结果相同

这就是组合, 使用匿名字段实现的组合. 使用组合后, 匿名字段拥有的所有方法都可以直接被调用, 而无需像h.girl.eat()这样写上字段类型来调用

重写/重载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main

import "fmt"

type boy struct {
}

func (b boy) eat() {
fmt.Println("The boy is eating an apple")
}

type girl struct {
}

func (g girl) eat() {
fmt.Println("The girl is eating an orange")
}

type human struct {
b boy
girl // 匿名字段
}

func (h human) eat() {
fmt.Println("The man is eating some strawberries")
}

func main() {
var h human
h.b.eat()
h.girl.eat()
h.eat()
}

这个demo仅比上个例子多了一个humaneat方法

执行结果:

1
2
3
The boy is eating an apple
The girl is eating an orange
The man is eating some strawberries

这次的执行结果中, h.eat() 的执行结果不再是 The girl is eating an orange, 而是 The man is eating some strawberries. 说明human下定义的eat方法重写了组合中同名的eat方法, 当该方法被直接调用时, 优先执行human下的eat方法. 此时如果还需要执行girl下的eat方法, 则需要先引用其数据类型, 再调用eat方法 -> h.girl.eat()

编辑器中也会提示你下面的方法重写了上面的方法