3.1 结构体 包 - hairyOwl/golangLearn GitHub Wiki
learn : 1
一 结构体
- go 语言仅支持封装,不支持继承和多态(用接口替代)
- go 语言没有class,只有struct
1.1 结构的定义
- 不论是地址还是结构本身,一律用'.'来访问成员
- go 语言没有构造函数,用工厂函数可以控制构造的特定格式
type treeNode struct {
value int
leftNode, RightNode *treeNode
}
func main(){
root = treeNode{value: 3}
root.left = &treeNode{}
root.Right = &treeNode{5, nil, nil}
root.Right.left = new(treeNode)
}
结构体创建在堆上还是栈上? c++ :局部变量分配在栈上,函数退出,局部变量就会立刻被销毁。如果想使用局部变量就要在堆上分配,需要手动释放 java : 几乎所有都分配在堆上 用new的。java用在堆上才有垃圾回收机制 go :由于go有垃圾回收器,回收受到编辑器和系统判断,所以不用在意是堆上还是栈上。局部变量如果在函数体外被使用就是堆上,没有使用就是栈上。同时局部变量在函数体外引用后,后续代码没有使用就会被回收。
1.2 为结构体定义方法
- 显示定义和命名方法接收者
- 只有使用指针才可以改变结构内容
- nil指针也能调用方法
值接收者 和 指针接收者使用场景
- 要改变内容必须使用指针接收者
- 结构过大也考虑使用指针接收者
- 如果有指针接收者,最好都是指针接收者
- 值接收者是go语言特有的
- 值/指针接收者 ,均可接收指针/值
func (node treeNode) print() { //(node treeNode)值传递
fmt.Print(node.value, " ")
}
func (node *treeNode) setValue(v int) { //值传递不能修改值 所以为了修改value,接收者用地址
node.value = v
}
二 封装
2.1 包 封装
2.1.2 包
- 每个目录一个包
- main包 包含可执行入口
- 为结构定义的方法必须和结构体在同一个包内,可以是不同文件
2.1.1封装
方法的可见性
- 名字驼峰
- 首字母大写:public 包括结构体名称、变量、方法
- 首字母小写:private 包括结构体名称、变量、方法
2.2 扩展已有类型
扩充系统类型和引用的第三方库的类型
- 定义别名
- 使用组合 常用
- 使用内嵌 语法糖
2.2.1 使用别名
//使用别名对已有类型进行扩展 用别名"queue"扩展原类型[]int,为其增加push(), pop(), isEmpty() 方法
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
}
验证:
func main() {
q := queue.Queue{1}
q.Push(2)
q.Push(3)
fmt.Printf("Pop: %d\n", q.Pop())
fmt.Printf("Pop: %d\n", q.Pop())
fmt.Println(q.IsEmpty())
fmt.Printf("Pop: %d\n", q.Pop())
fmt.Println(q.IsEmpty())
}
输出结果:
Pop: 1
Pop: 2
false
Pop: 3
true
————————————————
版权声明:本文为CSDN博主「Crownt」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/jt102605/article/details/82218256
2.2.2使用组合
type Node struct {
Data int
Left, Right *Node
}
func CreatNode(data int, left, right *Node) *Node {
return &Node{data, left, right}
}
func (node *Node) Print() {
fmt.Print(node.Data)
}
//中序遍历
func (node *Node) InOrder() {
if node == nil {
return
}
node.Left.InOrder()
node.Print()
node.Right.InOrder()
}
//通过使用组合的方式对原有类型进行扩展,将原结构体"Node"组合到"MyNode"中,在MyNode中增加了后序遍历的方法
type MyNode struct {
MyNode *tree.Node
}
//后序遍历
func (myNode *MyNode) PostOrder() {
if myNode == nil || myNode.MyNode == nil {
return
}
myLeft := MyNode{myNode.MyNode.Left}
myLeft.PostOrder()
myRight := MyNode{myNode.MyNode.Right}
myRight.PostOrder()
myNode.MyNode.Print()
}
————————————————
版权声明:本文为CSDN博主「Crownt」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/jt102605/article/details/82218256
2.2.3使用内嵌
/*
扩展已有类型
*/
// myTreeNode 扩展树遍历
type myTreeNode struct { //使用组合
node *tree.Node
}
// 后序遍历 左右中
func (n *myTreeNode) postOrder() {
if n == nil || n.node == nil {
return
}
left := myTreeNode{n.node.Left}
right := myTreeNode{n.node.Right}
left.postOrder()
right.postOrder()
n.node.Print()
}
// myTreeNode 扩展树遍历
type myTreeNode1 struct { //使用内嵌
*tree.Node //内嵌 省略node
}
// 后序遍历 左右中
func (n *myTreeNode1) postOrder1() {
if n == nil || n.Node == nil {
return
}
left := myTreeNode1{n.Left} //n.Node.Left 内嵌后可写为 n.Leftright := myTreeNode1{n.Right}
left.postOrder1()
right.postOrder1()
n.Print()
}
func (myNode *myTreeNode1) Traverse() {
fmt.Println("Shadowed Methods")
}
func main() {
root := myTreeNode1{&tree.Node{Value: 3}} //内嵌声明后
// 下方代码不用动 ,因为node 相当于平铺到myTreeNode1
root.Left = &tree.Node{}
root.Right = &tree.Node{5, nil, nil}
root.Right.Left = new(tree.Node) //指针和实例都可以用'.'
root.Left.Right = tree.CreateNode(7)
//fmt.Println(root) //{3 {0 nil nil} {5 nil nil} {0 nil nil}} x {3 0xc000008090 0xc0000080a8}√
fmt.Println("中序遍历")
root.Node.Traverse() //0 7 3 0 5
fmt.Println()
root.Traverse() //Shadowed
fmt.Println()
}