您好,登錄后才能下訂單哦!
這篇文章主要講解了“Go for-range的value值地址為什么每次都一樣”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Go for-range的value值地址為什么每次都一樣”吧!
循環語句是一種常用的控制結構,在 Go 語言中,除了 for
關鍵字以外,還有一個 range
關鍵字,可以使用 for-range
循環迭代數組、切片、字符串、map 和 channel 這些數據類型。
但是在使用 for-range
循環迭代數組和切片的時候,是很容易出錯的,甚至很多老司機一不小心都會在這里翻車。
先來看兩段很有意思的代碼:
如果我們在遍歷數組的同時向數組中添加元素,能否得到一個永遠都不會停止的循環呢?
比如下面這段代碼:
func main() { arr := []int{1, 2, 3} for _, v := range arr { arr = append(arr, v) } fmt.Println(arr) }
程序輸出:
$ go run main.go
1 2 3 1 2 3
上述代碼的輸出意味著循環只遍歷了原始切片中的三個元素,我們在遍歷切片時追加的元素并沒有增加循環的執行次數,所以循環最終還是停了下來。
第二個例子是使用 Go 語言經常會犯的一個錯誤。
當我們在遍歷一個數組時,如果獲取 range
返回變量的地址并保存到另一個數組或者哈希時,會遇到令人困惑的現象:
func main() { arr := []int{1, 2, 3} newArr := []*int{} for _, v := range arr { newArr = append(newArr, &v) } for _, v := range newArr { fmt.Println(*v) } }
程序輸出:
$ go run main.go
3 3 3
上述代碼并沒有輸出 1 2 3
,而是輸出 3 3 3
。
正確的做法應該是使用 &arr[i]
替代 &v
,像這種編程中的細節是很容易出錯的。
具體原因也并不復雜,一句話就能解釋。
對于數組、切片或字符串,每次迭代,for-range
語句都會將原始值的副本傳遞給迭代變量,而非原始值本身。
口說無憑,具體是不是這樣,還得靠源碼說話。
Go 編譯器會將 for-range
語句轉換成類似 C 語言的三段式循環結構,就像這樣:
// Arrange to do a loop appropriate for the type. We will produce // for INIT ; COND ; POST { // ITER_INIT // INDEX = INDEX_TEMP // VALUE = VALUE_TEMP // If there is a value // original statements // }
迭代數組時,是這樣:
// The loop we generate: // len_temp := len(range) // range_temp := range // for index_temp = 0; index_temp < len_temp; index_temp++ { // value_temp = range_temp[index_temp] // index = index_temp // value = value_temp // original body // }
切片:
// for_temp := range // len_temp := len(for_temp) // for index_temp = 0; index_temp < len_temp; index_temp++ { // value_temp = for_temp[index_temp] // index = index_temp // value = value_temp // original body // }
從上面的代碼片段,可以總結兩點:
在循環開始前,會將數組或切片賦值給一個新變量,在賦值過程中就發生了拷貝,迭代的實際上是副本,這也就解釋了現象 1。
在循環過程中,會將迭代元素賦值給一個臨時變量,這又發生了拷貝。如果取地址的話,每次都是一樣的,都是臨時變量的地址。
感謝各位的閱讀,以上就是“Go for-range的value值地址為什么每次都一樣”的內容了,經過本文的學習后,相信大家對Go for-range的value值地址為什么每次都一樣這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。