匿名组合
文章发布较早,内容可能过时,阅读注意甄别。
对于面向对象变成的支持,Go 语言设计的非常简洁且优雅。因为,Go 语言并没有沿袭传统面向对象编程中的诸多概念,比如继承(不支持继承,尽管匿名字段的内存布局和行为类似继承,但它并不是继承),虚函数,构造函数和析构函数,隐藏的 this 指针等。
传统面向对象核心概念可如图了解:
尽管 Go 语言中没有封装,继承,多态这些概念,但同样通过别的方式实现了这些特性:
- 封装:通过
方法
实现 - 继承:通过
匿名字段
实现 - 多态:通过
接口
实现
一般情况下,定义结构体的时候是字段名与其类型一一对应,实际上 Go 支持只提供类型,而不写字段名的方式,也就是匿名字段,也称为嵌入字段。
当匿名字段也是一个结构体的时候,那么这个结构体所拥有的全部字段都被隐式地引入了当前定义的这个结构体。
# 1,匿名字段。
package main
import "fmt"
type Person struct {
name string
sex byte
age int
}
type Student struct {
//内容重叠的,可以直接引用,只有类型,没有名字,就是匿名字段
//这样Student就会继承Person这个结构体里边的成员了
Person
id int
addr string
}
func main() {
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 2,匿名字段初始化。
package main
import "fmt"
type Person struct {
name string
sex byte
age int
}
type Student struct {
//内容重叠的,可以直接引用,只有类型,没有名字,就是匿名字段
//这样Student就会继承Person这个结构体里边的成员了
Person
id int
addr string
}
func main() {
//顺序初始化
var s1 = Student{Person{"yoyo", 'm', 18}, 1, "hangzhou"}
fmt.Println("s1 = ", s1)
//自动推导类型
s2 := Student{Person{"yoyo", 'm', 18}, 1, "hangzhou"}
//fmt.Println("s2 = ", s2)
//%+v显示详细信息
fmt.Printf("s2 = %+v\n", s2)
//指定成员初始化,没有初始化的默认为0
s3 := Student{addr: "hangzhou"}
fmt.Printf("s3 = %+v\n", s3)
s4 := Student{Person: Person{age: 18}, addr: "hangzhou"}
fmt.Printf("s4 = %+v\n", s4)
//s5 := Student{age: 18, addr: "hangzhou"} //err
}
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
34
35
36
37
38
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
34
35
36
37
38
# 3,成员的操作。
package main
import "fmt"
type Person struct {
name string
sex byte
age int
}
type Student struct {
Person
id int
addr string
}
func main() {
s1 := Student{Person{"yoyo", 'm', 18}, 1, "hangzhou"}
fmt.Println(s1.name, s1.sex, s1.age, s1.id, s1.addr)
//修改某个成员的值
s1.name = "eryajf"
s1.age = 22
s1.id = 5
fmt.Println(s1.name, s1.sex, s1.age, s1.id, s1.addr)
//修改Person里边的值
s1.Person = Person{"long", 'b', 20}
fmt.Println(s1.name, s1.sex, s1.age, s1.id, s1.addr)
}
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
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
# 4,同名字段。
其规则与前边的同名变量时一致的。
package main
import "fmt"
type Person struct {
name string
sex byte
age int
}
type Student struct {
Person
id int
addr string
name string
}
func main() {
//定义一个变量
var s Student
//如果定义的结构体引用的匿名字段有重名字段,那么在字段赋值的时候
//默认规则为就近原则,如果就近没有,再往外层匹配
s.name = "erya" //这个name是给Student赋值
s.sex = 'm'
s.age = 18
s.addr = "hangzhou"
fmt.Printf("s = %+v\n", s)
//如果要给Person里边的name字段赋值,则需要显式调用
s.Person.name = "long"
fmt.Printf("s = %+v\n", s)
}
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
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
# 5,非结构体匿名字段。
package main
import "fmt"
type mystr string //自定义类型,相当于别名
type Person struct {
name string
sex byte
age int
}
type Student struct {
Person //结构体类型匿名字段
int //基础类型匿名字段
mystr
}
func main() {
s := Student{Person{"yoyo", 'm', 18}, 666, "hangzhou"}
fmt.Printf("s = %+v\n", s)
s.Person = Person{"erya", 'm', 22}
fmt.Println(s.Person, s.int, s.mystr)
}
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
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
# 6,结构体指针类型匿名字段。
package main
import "fmt"
type Person struct {
name string
sex byte
age int
}
type Student struct {
*Person //指针类型
id int
addr string
}
func main() {
s1 := Student{&Person{"yoyo", 'm', 18}, 1, "hangzhou"}
fmt.Println(s1.name, s1.sex, s1.age, s1.id, s1.addr)
//通过new操作
var s2 Student
s2.Person = new(Person)
s2.name = "eryajf"
s2.age = 22
s2.id = 5
fmt.Println(s2.name, s2.sex, s2.age, s2.id, s2.addr)
}
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
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
上次更新: 2024/12/05, 21:39:23