下午面试,面试官让我写二叉树的中序遍历。
遥想半年前的秋招,我还只会C++,做啥题自然都是C++。
半年后的今天,经过了几个月的go语言学习,go学的咋样不敢说,反正C++是忘光了。。。
经过几秒钟的思考(其实我是想先定义个二叉树的结构体,可是实在是想不起来C的结构体怎么定义了。。。),我毅然决定,用go来写!
讲真,这是我第一次用go做题(别看我已经写了那么多篇go的文章,仿佛自己是个go语言专家)。。。好在,中序遍历的递归写法实在是没啥难的,所以,我很快就写出了下面这段代码:
func inOrder(root *TreeNode, array []int){
if root == nil {
return
}
inOrder(root.Left, array)
array = append(array, root.Val)
inOrder(root.Right, array)
}
面试官看了看,给出的评价是,恩,虽然细节上有些问题,但思路是对的,嘿嘿,那当然了,这我还能写不对,等下!细节有些问题是什么鬼???就这两行代码还能有错???我心想,肯定是这个面试官不懂go语言,随口一说的,所以当时也没追问这件事儿,万一一追问,他说他不会go,多尴尬啊对吧,哈哈哈。。。
然鹅,我是一个严谨的人,面试结束之后,我还是决定亲自跑一遍这段代码,用事实证明,我这几个月的go,不是白学的!
首先,我输入了一个这样的树:
文章图片
【go 当参数是slice,传值还是传指针()】这个中序遍历完,array那个slice应该变成[1,2,3,4]。
然鹅,结果是这样的:
文章图片
卧槽,怎么是个空的???
我开始努力回忆初学slice的时候,当时我还写过一篇blog啊,怎么会搞错呢。。。
文章图片
这段是当时我当时写的,看来看去,没错啊,slice里面存的是指向数组的指针,所以传slice的值进去,也是可以改变底层数组的啊,为啥我那么写就不行呢???
百思不得其解的我,百度了一下slice作为参数的用法,看到一个人说,如果slice在函数内部扩容了,就会#¥$&(他说的我没太看懂。。。) ,是啊,我给函数传进来的是一个容量为0的slice,在append的时候会扩容,而扩容的过程是:
- 先分配一段新的内存
- 然后把原来数组的内容拷贝过去
array = append(array, root.Val)
append的时候确实扩容了,slice里的指针也确实是变了,可是变了之后我又把新的赋值给array了啊,这个还是我外面传进来那个array啊,所以函数执行完外面那个array应该被修改了啊,没毛病啊。。。
这时我突然想到,array我是以值的形式传递进来的,也就是说,array里那个指向数组的指针,也是以值的形式传进来的,也就是说,函数内部修改了这个指针(注意是修改了指针本身,而不是修改了指针指向的内容),外面是看不到的!!!
阿西吧,原来如此啊。。。
于是,我把函数改成了传递slice指针进来,像下面这样:
func inOrder(root *TreeNode, array *[]int){
if root == nil {
return
}
inOrder(root.Left, array)
*array = append(*array, root.Val)
inOrder(root.Right, array)
}
再一运行,终于是对了。。。
天哪,我之前竟然还自信的以为是面试官不懂go,我简直就是个傻屌。。。
总结 最后总结一下吧,slice作为参数,如果以值的形式传递,确实可以在函数内部修改数组,但前提是,函数内部slice不会扩容,如果函数内部slice会扩容,那还是乖乖的传slice指针进去吧。
最后再说一句,我真的是是太年轻了。。。继续努力吧。。。
推荐阅读
- Go|Docker后端部署详解(Go+Nginx)
- GO|GO,GO,GO!
- Go成长之路|go中判断空字符串、nil和len(t)的用法
- go编译tools
- go grpc安装与使用
- goroutine 调度原理
- Go|Go进阶之路——复杂类型
- Go进阶之路——变量
- Go进阶之路——流程控制语句