溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Go?for-range的value值地址為什么每次都一樣

發(fā)布時間:2023-05-05 14:21:03 來源:億速云 閱讀:90 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要講解了“Go for-range的value值地址為什么每次都一樣”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Go for-range的value值地址為什么每次都一樣”吧!

    循環(huán)語句是一種常用的控制結(jié)構(gòu),在 Go 語言中,除了 for 關(guān)鍵字以外,還有一個 range 關(guān)鍵字,可以使用 for-range 循環(huán)迭代數(shù)組、切片、字符串、map 和 channel 這些數(shù)據(jù)類型。

    但是在使用 for-range 循環(huán)迭代數(shù)組和切片的時候,是很容易出錯的,甚至很多老司機一不小心都會在這里翻車。

    現(xiàn)象

    先來看兩段很有意思的代碼:

    無限循環(huán)

    如果我們在遍歷數(shù)組的同時向數(shù)組中添加元素,能否得到一個永遠(yuǎn)都不會停止的循環(huán)呢?

    比如下面這段代碼:

    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

    上述代碼的輸出意味著循環(huán)只遍歷了原始切片中的三個元素,我們在遍歷切片時追加的元素并沒有增加循環(huán)的執(zhí)行次數(shù),所以循環(huán)最終還是停了下來。

    相同地址

    第二個例子是使用 Go 語言經(jīng)常會犯的一個錯誤。

    當(dāng)我們在遍歷一個數(shù)組時,如果獲取 range 返回變量的地址并保存到另一個數(shù)組或者哈希時,會遇到令人困惑的現(xiàn)象:

    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

    正確的做法應(yīng)該是使用 &arr[i] 替代 &v,像這種編程中的細(xì)節(jié)是很容易出錯的。

    原因

    具體原因也并不復(fù)雜,一句話就能解釋。

    對于數(shù)組、切片或字符串,每次迭代,for-range 語句都會將原始值的副本傳遞給迭代變量,而非原始值本身。

    口說無憑,具體是不是這樣,還得靠源碼說話。

    Go 編譯器會將 for-range 語句轉(zhuǎn)換成類似 C 語言的三段式循環(huán)結(jié)構(gòu),就像這樣:

    // 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
    //   }

    迭代數(shù)組時,是這樣:

    // 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
    //   }

    從上面的代碼片段,可以總結(jié)兩點:

    • 在循環(huán)開始前,會將數(shù)組或切片賦值給一個新變量,在賦值過程中就發(fā)生了拷貝,迭代的實際上是副本,這也就解釋了現(xiàn)象 1。

    • 在循環(huán)過程中,會將迭代元素賦值給一個臨時變量,這又發(fā)生了拷貝。如果取地址的話,每次都是一樣的,都是臨時變量的地址。

    感謝各位的閱讀,以上就是“Go for-range的value值地址為什么每次都一樣”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對Go for-range的value值地址為什么每次都一樣這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI