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()  
    
}

BUG 🐞

链接🔗

  1. Go基础之面向对象(扩展已有类型篇)_go 扩展已有类型_Crownt的博客-CSDN博客