go语言仅支持封装,不支持继承和多态
go语言没有class,只有struct
1、初始化
package main
import "fmt"
type treeNode struct {
value int
left, right *treeNode
}
func main() {
var root treeNode
fmt.Println(root) // output:{0 <nil> <nil>}
root = treeNode{value:3}
root.left = &treeNode{}
root.right = &treeNode{5, nil, nil }
root.right.left = new(treeNode)
fmt.Println(root) // output:{3 0xc0420024a0 0xc0420024c0}
nodes := []treeNode{
{value:3},
{},
{6, nil, &root },
} // output:[{3 <nil> <nil>} {0 <nil> <nil>} {6 <nil> 0xc042002440}]
fmt.Println(nodes)
}
2、可以使用自定义工厂函数
package main
import "fmt"
type treeNode struct {
value int
left, right *treeNode
}
func createNode( value int ) *treeNode{
return &treeNode{value:value}
} // 返回的是局部变量的地址,go中是允许的
func main() {
var root treeNode
fmt.Println(root)
root = treeNode{value:3}
root.left = &treeNode{}
root.right = &treeNode{5, nil, nil }
root.right.left = new(treeNode)
root.left.right = createNode(8)
fmt.Println(root)
fmt.Println(*root.left.right) // output:{8 <nil> <nil>} root.right.right是指针,想看内容要加*
}
C++中,函数中局部变量分配在栈上,一旦函数退出,变量就被销毁,如果需要传出去,就要分配在堆上,分配在堆上的需要手动释放
Java中几乎所有东西都分配在堆上,都需要new
go语言不需要知道。。。。它会自己决定在哪里分配,如果需要返回就分配在堆上,后面会参与垃圾回收,如果不需要返回,就分配在栈上。
3、结构的方法
package main
import "fmt"
type treeNode struct {
value int
left, right *treeNode
}
// struct的方法,需要在函数名前加(node treeNode),叫做接受者,相当于其他语言的this,功能和普通函数的参数差不多
func (node treeNode) print() {
fmt.Println(node.value)
}
// 普通函数
func print2(node treeNode) {
fmt.Println(node.value)
}
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)
root.left.right = createNode(8)
root.print() // output:3 和普通函数只是调用方法不太相同,其他差不多。
print2(root) // output:3
}
接收者相当于普通函数的传参,也是值传递
package main
import "fmt"
type treeNode struct {
value int
left, right *treeNode
}
func (node treeNode) print() {
fmt.Println(node.value)
}
// 值传递,所以并不能改变value值
func (node treeNode) setValue( value int ) {
node.value = value
}
// 传地址,用指针作为接受者,能够改变value值
func (node *treeNode) realSetValue( value int ) {
node.value = value
}
// nil指针也可以调用方法,传进去的可以是nil,只要传进去之后再判断是不是nil就可以
func (node *treeNode) traverse() {
if node == nil {
return
}
// 如果是C++等语言,需要先判断node.left != None,才能调用,但因为go中nil也可调用方法,so不需要判断
node.left.traverse()
node.print()
node.right.traverse()
}
func createNode( value int ) *treeNode{
return &treeNode{value:value}
}
func main() {
var root treeNode
fmt.Println(root)
root = treeNode{value:3}
root.left = &treeNode{}
root.right = &treeNode{5, nil, nil }
root.right.left = new(treeNode)
root.left.right = createNode(8)
// 值接受者和指针接受者并不影响调用
root.left.print() // output:0
root.left.setValue(7) // 调用时,拷贝一份传给函数
root.left.print() // output:0 其value值并没有改变
root.left.realSetValue(7) // 调用时,会把地址给函数
root.left.print() // output:7 能够改变
// 取地址后,也可以调用两个函数,编译器会根据接受者类型自动判断如果给函数传参
pRoot := &root
pRoot.print() // output: 3
pRoot.realSetValue(20)
pRoot.print() // output: 20
root.traverse() // output: 7 8 20 0 5
}
需要改变内容必须使用指针接受者,结构过大考虑使用指针接受者,建议如果有指针接受者,最好都使用指针接受者