面向对象
概述:go语言仅支持封装,不支持继承和多态,所以go语言没有class,只有struct
下面我将详细整理下struct的用法,通过代码将学习的知识巩固下,如有错误,请指出!!!
一.结构体和方法
type TreeNode struct {
value int
Left, Right *TreeNode
}
func main() {
var root TreeNode
root = TreeNode{value: 3}
root.Left = &TreeNode{}
root.Right = &TreeNode{5, nil, nil}
root.Right.Left = new(TreeNode)
nodes := []TreeNode{
{value: 3, Left: &root},
{},
{6, nil, &root},
}
// 下面这个定义大家细品
var nillRoot *TreeNode
fmt.Println(nillRoot) // 输出结果是:<nil>
doRoot := new(TreeNode)
fmt.Println(doRoot) // 输出结果是:&{0 <nil> <nil>}
}
- 不论地址还是结构体本身,一律使用.来访问成员
// 工厂函数
func createNode(value int) *TreeNode {
return &TreeNode{Value: value}
}
root.Right.Left = createNode(2)
- 使用自定义工厂函数
- 注意返回了局部变量的地址
- 结构创建在堆上还是栈上? 答案:不需要知道(有可能在堆上也有可能在栈上,由go的垃圾回收机制清理)
// 为结构定义方法
func (node TreeNode) print() {
fmt.Println(node.Value)
}
func (node *TreeNode) setValue(value int) {
node.Value = value
}
- 显示定义和命名方法接受者
- 只有使用指针才可以改变结构内容,如setValue方法
- nil指针也可以调用方法
- 值接收者和指针接收者(1.要改变内容必须使用指针接收者2.结构过大也要考虑使用指针接受者)
二 .包和封装
封装的特点:
- 名字一般使用CamelCase
- 首字母大写public 针对 包
- 首字母小写pravite 针对 包
包的特点:
- 每个目录一个包(包名不需要和目录名一致)
- main包包含可执行入口
- 为结构定义的方法必须放在一个包内
- 可以是不同的文件
三.扩展已有的类型
如何扩充系统类型或者别人的类型?
- 定义别名(自己定义一个包)
- 使用组合(如下代码所示)
// 使用组合的方式
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()
}
func main() {
var root tree.Node
root = tree.Node{Value: 3}
root.Left = &tree.Node{}
root.Right = &tree.Node{5, nil, nil}
root.Left.Right = &tree.Node{}
root.Right.Left = new(tree.Node)
root.Right.Left = tree.CreateNode(2)
root.Left.Right.SetValue(4)
// 使用组合的方式
root.Traverse()
fmt.Println()
myroot := myTreeNode{&root}
myroot.postOrder()
// myTreeNode{&root}.postOrder() // 这样写会报错:只有变量才能拿地址
}
- 使用内嵌方式扩展已有类型 (有点类似继承)
// 内嵌类型扩展
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 (myTreeNode *myTreeNode) Traverse() {
fmt.Println("this is shadowed")
}
func main() {
// 使用内嵌方式
root := myTreeNode{&tree.Node{Value: 3}}
root.Left = &tree.Node{}
root.Right = &tree.Node{5, nil, nil}
root.Left.Right = &tree.Node{}
root.Right.Left = new(tree.Node)
root.Right.Left = tree.CreateNode(2)
root.Left.Right.SetValue(4)
// root.postOrder()
// 原有的
root.Node.Traverse()
//重载的
root.Traverse()
}