面向对象:
go只支持封装,不支持继承和多态。
go语言没有class,只有struct。
type treeNode struct {
value int
leftNode,rightNode *treeNode
}
结构体的定义
结构体没有构造函数,可以自定义工厂函数。
func createTreeNode(value int) *treeNode {
return &treeNode{value: value}
}
调用:
var root treeNode
fmt.Println(root)
root = treeNode{3,nil,nil}
root.leftNode=createTreeNode(5)
控制台打印:
{0 <nil> <nil>}
&{5 <nil> <nil>}
Process finished with exit code 0
问题:结构体创建在堆上还是栈上?
在go语言中,不需要关系变量创建在堆栈的哪个位置,编译器会自动决定创建的位置,如果一个变量需要返回,编译器会在堆上创建,如果不需要返回,则会创建在栈上,因为go语言有垃圾回收机制,这一点不用担心。
为结构体定义方法:
func (node treeNode) print() {
fmt.Println(node.value)
}
注意方法前面加上了 (node treeNode) 表示该方法属于treeNode这个结构体。
调用:
var root treeNode
fmt.Println(root)
root = treeNode{3,nil,nil}
root.leftNode=&treeNode{}
root.rightNode=&treeNode{5,nil,nil}
root.rightNode.leftNode=new(treeNode)
root.leftNode.rightNode=createTreeNode(2)
root.print()
控制台:
{0 <nil> <nil>}
3
{3 0xc00004c460 0xc00004c480}
Process finished with exit code 0
打印出了root节点的value:3
再定义一个修改节点value的方法:
func (node treeNode) setValue(value int) {
node.value=value
}
调用:
var root treeNode
fmt.Println(root)
root = treeNode{3,nil,nil}
root.leftNode=&treeNode{}
root.rightNode=&treeNode{5,nil,nil}
root.rightNode.leftNode=new(treeNode)
root.leftNode.rightNode=createTreeNode(2)
root.print()
root.rightNode.leftNode.setValue(4)
fmt.Println(root.rightNode.leftNode)
fmt.Println(root)
控制台打印:
{0 <nil> <nil>}
3
&{0 <nil> <nil>}
{3 0xc0000044c0 0xc0000044e0}
Process finished with exit code 0
可以看到,值并没有被改掉。
为什么值没有被改掉呢,因为在go语言中,只有值传递,传进去的node被拷贝了一份新的,改变的值自然影响不到外面的结果,改造一下:
func (node *treeNode) setValue(value int) {
node.value=value
}
调用:
var root treeNode
fmt.Println(root)
root = treeNode{3,nil,nil}
root.leftNode=&treeNode{}
root.rightNode=&treeNode{5,nil,nil}
root.rightNode.leftNode=new(treeNode)
root.leftNode.rightNode=createTreeNode(2)
root.print()
root.rightNode.leftNode.setValue(4)
fmt.Println(root.rightNode.leftNode)
fmt.Println(root)
控制台:
{0 <nil> <nil>}
3
&{4 <nil> <nil>}
{3 0xc00004c460 0xc00004c480}
Process finished with exit code 0
可以看到,结果已经改变了。
因为setValue要求的参数从treeNode变成了一个treeNode的地址,传进去的为外面node的地址,改变的是同一份数据吗,所以node的值发生了改变。go的方便之处在于,参数虽然是指针,但是依然可以直接点出来调用,没有复杂的过程,取值取地址等操作。调用的时候也不用做任何修改,按道理是应该传进去一个指针的,但是编译器会知道怎么做,他发现参数是指针的时候,会自动取当前参数的地址当作参。所以调用的方式也和原来一样。当他发现参数是值类型时,会拷贝一份传进去,这也就是为什么第一种方式改不掉value的值。
pRoot :=&root
pRoot.print()
pRoot.setValue(1000)
pRoot.print()
控制台:
3
1000
Process finished with exit code 0
这样的操作时合法的,虽然pRoot 为root的地址,但是依然可以直接当作一个值来操作。
遍历一下树:
func (node *treeNode) traverse() {
if node == nil{
return
}
node.leftNode.traverse()
node.print()
node.rightNode.traverse()
}
调用:
var root treeNode
fmt.Println(root)
root = treeNode{3,nil,nil}
root.leftNode=&treeNode{}
root.rightNode=&treeNode{5,nil,nil}
root.rightNode.leftNode=new(treeNode)
root.leftNode.rightNode=createTreeNode(2)
root.print()
root.rightNode.leftNode.setValue(4)
fmt.Println(root.rightNode.leftNode)
fmt.Println(root)
// 3
//0 5
// 2 0
fmt.Println("*****************")
root.traverse()
}
控制台:
*****************
nodeValue: 0
nodeValue: 2
nodeValue: 3
nodeValue: 4
nodeValue: 5
Process finished with exit code 0
总结:
要改变内容必须使用指针来接受参数。
结构过大也考虑使用指针接收,因为过大的话拷贝会占用太多资源。
一致性:如果有指针接收者,最好都用指针接收。