一、封装和包

  • 名字一般使用CamelCase
  • 首字母大写: public
  • 首字母小写: private

publicprivate 是针对“包”来说的

  • 每个目录一个包:包名和目录名不一样要一样,每一个目录只有一个包
  • main 包:包含可执行入口,只有main包才可以执行main函数
  • 为结构定义的方法,必须放在同一个包内,可以是不同文件

二、包-扩展已有类型

如何扩充系统类型或者别人的类型,两种方法扩展:

1. 定义别名扩充类型(最简单)

slice 定义一个别名 Queue,然后进行扩充

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
}
package main

import (
    "fmt"
    queue "learngo/14queue"
)

func main() {
    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())
}

2. 使用组合扩充类型(最常用)

package main

import (
    "fmt"
    "learngo/tree"
)

// 组合的方式扩展类型,把原先的类型,当作新类型的一个参数
type myTreeNode struct {
    node *tree.Node
}

// 后序遍历
func (myNode *myTreeNode) postOrder() {
    if myNode == nil || myNode.node == nil {
        return
    }
    left := myTreeNode{myNode.node.Left}
    right := myTreeNode{myNode.node.Right}

    left.postOrder()
    right.postOrder()
    myNode.node.Print()
}

func main() {
    var root tree.Node
    root = tree.Node{Value: 3}
    root.Left = &tree.Node{}
    root.Right = &tree.Node{Value: 5}

    node := myTreeNode{&root}
    node.postOrder()
}

3. 使用内嵌(省下许多代码)

内嵌是在组合的情况下,修改为内嵌的

package main

import (
    "fmt"
    tree "learngo/13tree"
)

type myTreeNode struct {
    // Embedding 这种不指定名称的方式,就是内嵌
    *tree.Node
}

// 后序遍历
func (myNode *myTreeNode) postOrder() {
    // 注意这里,判断的时候还是要用 myNode.Node
    if myNode == nil || myNode.Node == nil {
        return
    }
    left := myTreeNode{myNode.Node.Left} // myNode.Node 方式访问到内嵌类型
    right := myTreeNode{myNode.Right}    // 直接通过访问 myNode 也能实现效果,这就是内嵌的好处,可以直接调到 myNode.Node 内容

    left.postOrder()
    right.postOrder()
    myNode.Print()
}

func (myNode *myTreeNode) Traverse() {
    fmt.Println("myTreeNode 的 Traverse")
}

func main() {
    // root 直接初始化为 myTreeNode类型,下面直接调用roo就行
    root := myTreeNode{&tree.Node{Value: 3}}
    root.Left = &tree.Node{}
    root.Right = &tree.Node{Value: 5}

    fmt.Println("后序遍历")
    root.postOrder()

    root.Node.Traverse() // 这里调的是root.Node的Traverse

    // 这里打印的 myTreeNode 定义的 Traverse
    // 虽然他们看起来像继承,其实就是一个语法糖
    // 如果myTreeNode定义了同名方法,就调用自己定义的同名方法,否则调用Node的方法
    root.Traverse()

    // go 不支持下面的写法,其它语言继承可以,这也是和继承的一个区别
    // 如果go也想实现下面的功能,使用的是接口
    // var baseRoot *tree.Node
    // baseRoot := &root
}