go语言只有封装,没有继承和多态
结构体定义方法
package main
import "fmt"
type treeNode struct {
value int
left, right *treeNode
}
func createNode(value int) *treeNode {
return &treeNode{value: value}
}
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},
{6, nil, &root},
{},
}
root.left.right = createNode(2)
fmt.Println(nodes)
fmt.Println(root.left.right.value)
}
打印结果:
可以看到:
func createNode(value int) *treeNode {
return &treeNode{value: value}
}
这是一个工厂函数,和其他语言的构造函数一样,那么,这里就有个疑点了,在其他语言中,例如C++、Java,这些语言的构造函数都是在class里面的,而go中这个工厂函数和普通函数一样,只是返回一个局部变量,这在其他语言中明显是错误的,但是,这在go中是被允许的。
例如Java,通常都是new一个新的对象,Java采用的是用堆取储存局部变量,这样它的垃圾回收机制就可以发挥作用,那go的局部变量存储在哪里呢?我们不需要知道,因为go中的垃圾回收机制会自动帮我们销毁这些局部变量。
在上面的代码中,可以看到我们通过结构体定义了一颗树出来,那我们怎么打印处这颗树呢?
func (node treeNode) print() {
fmt.Print(node.value)
}
可以用这个函数,这个函数就相当于一个普通函数,不同的是这个函数有一个接收者(node treeNode)
这样我们就可以用root.print()
打印出root的value
这个函数不用接收者也可以,可以改写为
func print(node treeNode) {
fmt.Print(node.value)
}
那么调用方法就变成了print(root)
但在设定值的时候,就要注意了,go语言是值传递,如果构造函数是这样的:
func (node treeNode) setValue(value int) {
node.value = value
}
那么它并不会改变node的value,必须要传一个指针进去,才能实现对value的设置,
即:要改变内容的时候必须使用指针接收者。
另外,在考虑性能方面的时候,当结构体过大时,也考虑使用指针接收者
再有的是有一个一致性原则,当有采用指针接收者时,统一采用指针接收者
func (node *treeNode) setValue(value int) {
node.value = value
}
在调用的时候,编译器会根据你设定的接收者去传递值,不用看到是指针类型的参数,就特意去取地址,就如:
proot := &root
proot.setValue(100)
proot.print()
proot.setValue(300)
proot.print()
是可以运行成功的
需要注意的是,go语言中niu指针也可以调用方法
func (node *treeNode) setValue(value int) {
if node == nil {
fmt.Println("Setting value to the niu node ")
}
node.value = value
}
var Rrot *treeNode
Rrot.setValue(200)
Rrot = &root
Rrot.setValue(300)
Rrot.print()
运行结果:
可以看到,成功打印了那句话,说明了nil指针是可以成功传如函数中,报错的原因是niu指针执行不了node.value = value,需要补一个return
func (node *treeNode) setValue(value int) {
if node == nil {
fmt.Println("Setting value to the niu node ")
return
}
node.value = value
}
结果: