第十一节:面向对象(结构体和方法)

面向对象:

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

总结:

要改变内容必须使用指针来接受参数。

结构过大也考虑使用指针接收,因为过大的话拷贝会占用太多资源。

一致性:如果有指针接收者,最好都用指针接收。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值