面向对象
1 | type TreeNode struct { |
- go语言仅支持封装,不支持继承和多态
- 继承和多态使用接口实现
- go语言没有class ,只有struct
1 | package main |
new (Type) *Type
函数为内建函数,接受值为类型,会在内部申请一块该类型的空间并进行清零,然后返回指向该地址的指针,是一个值为空的结构的地址&{},和nil不一样。
上面演示了创建结构的创建以及初始化,初始化时可以只给个别值赋值,则其余值为该类型的零值,或者都不赋初值。赋值时采用类似字典的方式k:v 的形式进行赋值。
也可以使用变量名.结构体内部变量
的方式来赋值
- 不论地址还是结构本身,一律使用.来访问成员
1 | func createNode(value int) *treeNode{ |
- 使用自定义工厂函数
- 注意返回了局部变量地址!(局部变量在函数执行结束后会进行垃圾回收,函数内声明的局部变量会消失,局部变量地址也就没有意义了)但是这在go语言中是没有问题的
Go语言的结构创建在堆上还是栈上?
- 不需要知道
- 堆上分配的会参与垃圾回收,Go语言会自动根据变量是否会被使用决定分配的情况,像上面的函数中的treeNode在函数退出后并没有消失,所以放在堆中,参与垃圾回收,当不在被使用后会被回收,而不是像c++中的函数内是局部变量,一旦退出函数后,就消失。
1 | // 结构方法一: |
(node treeNode)
是调用的结构对象,可以理解为将原先func print(node treeNode)
后面的参数前移动了,print()
函数名之后依然是可以放其他参数的,总的来说就是,将调用者前移,其他的和普通的函数调用没有区别。
1 | // 结构方法二: |
因为Go语言都是值传递,所以,若在此处使用值类型,对node的修改是不会反映到实际节点上的,因为在调用的时候是将节点重新复制了一份去操作的。所以,若设计到修改,都需传递指针。
因为结构方法node可以是值传递接受值,也可能是指针传递接受地址,所以,Go编译器对结构方法的调用相当智慧:
1 | // 结构方法的使用 |
¶结构方法小结
-
显示定义和命名方法的接受者
-
只有指针才能改变结构内容
-
nil指针也可以调用方法!
1
2
3
4
5
6
7
8
9
10func (node *treeNode) setValue(value int){
if node == nil {
fmt.Println("Setting value to nill " +
"node. Ignore")
return
}
node.Value = value
}
var pRoot *treeNode // 指针类型的默认初始值为nil
fmt.Println(pRoot.setValue(200))会正常执行,因为nil也是可以直接使用的,但是要注意,nil直接使用了,但是这里不能取到value,所以做一下判断,直接return结束函数。
¶遍历树
1 | func (node *treeNode) traverse() { |
因为Go中的nil可以进行运算,所以traverse()处不需要判断,只要进入方法后,判断一下就行。
¶值接收者vs指针接收者
接收者是在结构
方法中的概念,在结构方法中用来代表结构对象,类似于Python类实例方法中的self
- 要改变内容的必须使用指针接收者
- 结构过大也考虑使用指针就收者,因为使用值接收者的话要拷贝,结构过大,造成资源浪费
- 一致性:如有指针接收者,最好都是指针接收者
- 值接收者是Go语言特有
- 值/指针接收者均可接收值/指针,Go编译器会自动转换
- 一般较多使用的时候都是指针接受者 ,因为涉及到改变内容的操作较多