下午面試,面試官讓我寫二叉樹的中序遍歷。
遙想半年前的秋招,我還只會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,不是白學的!
首先,我輸入了一個這樣的樹:
這個中序遍歷完,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指針進去吧。
最後再說一句,我真的是是太年輕了。。。繼續努力吧。。。