继承
# 1. 继承的介绍
# 继承的引入:
当多个结构体存在相同的属性(字段)和方法时,可以从这些结构体中抽象出结构体,在该结构体中定义这些相同的属性和方法,其它的结构体不需要重新定义这些属性和方法,只需嵌套一个匿名结构体即可。也就是说:在Golang中,如果一个struct嵌套了另一个匿名结构体,那么这个结构体可以直接访问匿名结构体的字段和方法,从而实现了继承特性。
继承的优点: 提高代码的复用性、扩展性
# 代码示例
package main
import (
"fmt"
)
// Animal 定义动物结构体:
type Animal struct {
Age int
Weight float32
}
// Shout 给Animal绑定方法:喊叫:
func (an *Animal) Shout() {
fmt.Println("我可以大声喊叫")
}
// ShowInfo 给Animal绑定方法:自我展示:
func (an *Animal) ShowInfo() {
fmt.Printf("动物的年龄是:%v,动物的体重是:%v", an.Age, an.Weight)
}
// Cat 定义结构体:Cat
type Cat struct {
//为了复用性,体现继承思维,嵌入匿名结构体:——》将Animal中的字段和方法都达到复用
Animal
}
// 对Cat绑定特有的方法:
func (c *Cat) scratch() {
fmt.Println("我是小猫,我可以挠人")
}
func main() {
//创建Cat结构体示例:
cat := &Cat{}
cat.Animal.Age = 3
cat.Animal.Weight = 10.6
cat.Animal.Shout()
cat.Animal.ShowInfo()
cat.scratch()
fmt.Println(cat)
}
/*
我可以大声喊叫
动物的年龄是:3,动物的体重是:10.6我是小猫,我可以挠人
&{{3 10.6}}
*/
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
39
40
41
42
43
44
45
46
47
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
39
40
41
42
43
44
45
46
47
# 2. 多继承
Golang中支持多继承:如一个结构体嵌套了多个匿名结构体,那么该结构体可以直接访问嵌套的匿名结构体的字段和方法,从而实现了多重继承。为了保证代码的简洁性,建议大家尽量不使用多重继承,很多语言就将多重继承去除了,但是Go中保留了。
package main
import (
"fmt"
)
type A struct {
a int
b string
}
type B struct {
c int
d string
}
// C C同时继承AB结构体
type C struct {
A
B
}
func main() {
//构建C结构体实例:
c := C{A{10, "aaa"}, B{20, "ccc"}}
fmt.Println(c)
}
/*
{{10 aaa} {20 ccc}}
*/
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
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
# 3. 注意事项
# 1. 结构体可以使用嵌套匿名结构体所有的字段和方法,即:首字母大写或者小写的字段、方法,都可以使用。
package main
import (
"fmt"
)
// Animal1 定义动物结构体:
type Animal1 struct {
Age int
weight float32
}
// Shout1 给Animal1绑定方法:喊叫:
func (an *Animal1) Shout1() {
fmt.Println("我可以大声喊叫")
}
// 给Animal1绑定方法:自我展示:
func (an *Animal1) showInfo() {
fmt.Printf("动物的年龄是:%v,动物的体重是:%v", an.Age, an.weight)
}
// Cat1 定义结构体:Cat1
type Cat1 struct {
//为了复用性,体现继承思维,嵌入匿名结构体:——》将Animal1中的字段和方法都达到复用
Animal1
}
// 对Cat1绑定特有的方法:
func (c *Cat1) scratch() {
fmt.Println("我是小猫,我可以挠人")
}
func main() {
//创建Cat1结构体示例:
// 【1】结构体可以使用嵌套匿名结构体所有的字段和方法,即:首字母大写或者小写的字段、方法,都可以使用。
Cat1 := &Cat1{}
Cat1.Animal1.Age = 3
Cat1.Animal1.weight = 10.6
Cat1.Animal1.Shout1()
Cat1.Animal1.showInfo()
Cat1.Age = 31
Cat1.weight = 10.61
Cat1.Shout1()
Cat1.showInfo()
Cat1.scratch()
}
/*
我可以大声喊叫
动物的年龄是:3,动物的体重是:10.6我可以大声喊叫
动物的年龄是:31,动物的体重是:10.61我是小猫,我可以挠人
*/
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 2. 匿名结构体字段访问可以简化
cat.Age --->cat对应的结构体中找是否有Age字段,如果有直接使用,如果没有就去找嵌入的结构体类型中的Age(如果继承中定义有重复的字段和方法建议使用第一种。)
# 3. 当结构体和匿名结构体有相同的字段或者方法时,编译器采用就近访问原则访问,如希望访问匿名结构体的字段和方法,可以通过匿名结构体名来区分
package main
import (
"fmt"
)
// Animal2 定义动物结构体:
type Animal2 struct {
Age int
weight float32
}
// Shout 给Animal2绑定方法:喊叫:
func (an *Animal2) Shout() {
fmt.Println("我可以大声喊叫")
}
//给Animal2绑定方法:自我展示:
func (an *Animal2) showInfo() {
fmt.Printf("动物的年龄是:%v,动物的体重是:%v", an.Age, an.weight)
}
// Cat2 定义结构体:Cat2
type Cat2 struct {
//为了复用性,体现继承思维,嵌入匿名结构体:——》将Animal2中的字段和方法都达到复用
Animal2
Age int
}
func (c *Cat2) showInfo() {
fmt.Printf("~~~~~~~~动物的年龄是:%v,动物的体重是:%v", c.Age, c.weight)
}
// 对Cat2绑定特有的方法:
func (c *Cat2) scratch() {
fmt.Println("我是小猫,我可以挠人")
}
func main() {
//创建Cat2结构体示例:
// Cat2 := &Cat2{}
// Cat2.Age = 3
// Cat2.weight = 10.6
// Cat2.Shout()
// Cat2.showInfo()
// Cat2.scratch()
Cat2 := &Cat2{}
Cat2.weight = 9.4
Cat2.Age = 10 //就近原则
Cat2.Animal2.Age = 20
Cat2.showInfo() //就近原则
Cat2.Animal2.showInfo()
}
/*
~~~~~~~~动物的年龄是:10,动物的体重是:9.4动物的年龄是:20,动物的体重是:9.4
*/
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# 4. 如嵌入的匿名结构体有相同的字段名或者方法名,则在访问时,需要通过匿名结构体类型名来区分。
package main
import (
"fmt"
)
type A struct {
a int
b string
}
type B struct {
c int
d string
a int
}
type C struct {
A
B
}
func main() {
//构建C结构体实例:
c := C{A{10, "aaa"}, B{20, "ccc", 50}}
fmt.Println(c.b)
fmt.Println(c.d)
fmt.Println(c.A.a)
fmt.Println(c.B.a)
}
/*
aaa
ccc
10
50
*/
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
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
# 5. 结构体的匿名字段可以是基本数据类型
# 6. 嵌套匿名结构体后,也可以在创建结构体变量(实例)时,直接指定各个匿名结构体字段的值。
# 7. 嵌入匿名结构体的指针也是可以的
# 8. 结构体的字段可以是结构体类型的。(组合模式)
package main
import (
"fmt"
)
type A struct {
a int
b string
}
type B struct {
c int
d string
a int
}
type C struct {
*A
*B
}
type D struct {
a int
b string
c B
}
func main() {
//构建C结构体实例:
//c := C{A{10, "aaa"}, B{20, "ccc", 50}}
c := C{&A{a: 10, b: "aaa"}, &B{c: 20, d: "ccc", a: 50}}
fmt.Println(c.b)
fmt.Println(c.d)
fmt.Println(c.A.a)
fmt.Println(c.B.a)
d := D{10, "xxx", B{1, "xx", 2}}
fmt.Println(d)
fmt.Println(d.c.a)
}
/*
aaa
ccc
10
50
{10 xxx {1 xx 2}}
2
*/
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
39
40
41
42
43
44
45
46
47
48
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
39
40
41
42
43
44
45
46
47
48
编辑 (opens new window)