扩展已有类型或系统类型
# 扩展已有类型
Java 等面向对象语言里,对一个类进行扩展类型,使用继承就可以实现;但是
Go
语言里面没有继承,我们该如何进行扩展类型呢?
方法:
- 定义别名
- 使用组合
比如,遍历一个树节点,前面已经实现了一个中序遍历,假如我们还需要实现前序、后按序遍历怎么办?
package tree
func (node *Node) Traverse() {
if node == nil {
return
}
// 中序遍历 左中右
node.Left.Traverse()
node.Print()
node.Right.Traverse()
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
组合方式:
type myTreeNode struct {
node *tree.Node
}
func (myNode *myTreeNode) postOrder() {
if myNode == nil || myNode.node == nil {
return
}
left := myTreeNode{myNode.node.Left}
left.postOrder()
right := myTreeNode{myNode.node.Right}
right.postOrder()
myNode.node.Print()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
定义别名案例:
package queue
type Queue []int
func (q *Queue) Push(v int) {
*q = append(*q, v)
}
func (q *Queue) Pop() int {
head := (*q)[0]
*q = (*q)[1:]
return head
}
func (q *Queue) IsEmpty() bool {
return len(*q) == 0
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main
import (
"fmt"
"github.com/wujie/base_learn/queue"
)
func main() {
// 这个q和最后一个方法执行完的不是一个因为他们是指针类型
q := queue.Queue{1}
q.Push(2)
q.Push(3)
fmt.Println(q.Pop())
fmt.Println(q.Pop())
fmt.Println(q.IsEmpty())
fmt.Println(q.Pop())
fmt.Println(q.IsEmpty())
}
// 结果
1
2
false
3
true
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
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
# 使用内嵌的方式来扩展已有的类型
Embedding(内嵌)
type myTreeNode struct {
*tree.Node // Embedding 内嵌 语法糖
}
1
2
3
2
3
即将前面的node
进行省略。
它默认的名字为Node
,无视前面的*tree.*
代码可简写为下面的方式
func (myNode *myTreeNode) postOrder() {
if myNode == nil || myNode.Node == nil {
return
}
left := myTreeNode{myNode.Left}
left.postOrder()
right := myTreeNode{myNode.Right}
right.postOrder()
myNode.Print()
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
因此,myNode
不仅拥有Node
的变量和方法,还有自己的postOrder
方法可以进行调用
main
函数也可以进行简写
package main
import (
"fmt"
"github.com/wujie/base_learn/tree"
)
type myTreeNode struct {
*tree.Node // Embedding 内嵌 语法糖
}
func (myNode *myTreeNode) postOrder() {
if myNode == nil || myNode.Node == nil {
return
}
left := myTreeNode{myNode.Left}
left.postOrder()
right := myTreeNode{myNode.Right}
right.postOrder()
myNode.Print()
}
func main() {
// 建立了一个根节点
root := myTreeNode{&tree.Node{Value: 3}}
root.Left = &tree.Node{}
root.Right = &tree.Node{Value: 5}
root.Right.Left = new(tree.Node)
root.Left.Right = tree.CreateNode(2)
root.Right.Left.SetValue(4)
root.Traverse()
fmt.Println()
root.postOrder()
fmt.Println()
}
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
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
# 方法重载?
我们在文件中又写了一个同名的一个遍历函数,且 IDE 给我们标志为一个shadowed method
func (myNode *myTreeNode) Traverse() {
fmt.Println("This method is shadowed.")
}
1
2
3
2
3
所以下面我们调用的Traverse
方法就是本文件里的这个。但是我们也可以加上root.Node.Traverse()
进行调用真正的中序遍历。
func main() {
// 建立了一个根节点
root := myTreeNode{&tree.Node{Value: 3}}
root.Left = &tree.Node{}
root.Right = &tree.Node{Value: 5}
root.Right.Left = new(tree.Node)
root.Left.Right = tree.CreateNode(2)
root.Right.Left.SetValue(4)
root.Node.Traverse()
root.Traverse()
fmt.Println()
root.postOrder()
fmt.Println()
}
// 结果
0 2 3 4 5 This method is shadowed.
2 0 4 5 3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
编辑 (opens new window)
上次更新: 2022/03/20, 23:11:24