go 當參數是slice,傳值還是傳指針?

下午面試,面試官讓我寫二叉樹的中序遍歷。

遙想半年前的秋招,我還只會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指針進去吧。

最後再說一句,我真的是是太年輕了。。。繼續努力吧。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章