日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
為什么 Go For-Range 的 value 值地址每次都一樣?

循環(huán)語句是一種常用的控制結(jié)構(gòu),在 Go 語言中,除了 for 關(guān)鍵字以外,還有一個(gè) range 關(guān)鍵字,可以使用 for-range

目前成都創(chuàng)新互聯(lián)公司已為上千多家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)絡(luò)空間、網(wǎng)站托管、服務(wù)器租用、企業(yè)網(wǎng)站設(shè)計(jì)、羅定網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。

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

具體是怎么翻的呢?我們接著看。

現(xiàn)象

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

無限循環(huán)

如果我們?cè)诒闅v數(shù)組的同時(shí)向數(shù)組中添加元素,能否得到一個(gè)永遠(yuǎn)都不會(huì)停止的循環(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)只遍歷了原始切片中的三個(gè)元素,我們?cè)诒闅v切片時(shí)追加的元素并沒有增加循環(huán)的執(zhí)行次數(shù),所以循環(huán)最終還是停了下來。

相同地址

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

當(dāng)我們?cè)诒闅v一個(gè)數(shù)組時(shí),如果獲取 range 返回變量的地址并保存到另一個(gè)數(shù)組或者哈希時(shí),會(huì)遇到令人困惑的現(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é)是很容易出錯(cuò)的。

原因

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

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

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

Go 編譯器會(huì)將 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ù)組時(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é)兩點(diǎn):

  1. 在循環(huán)開始前,會(huì)將數(shù)組或切片賦值給一個(gè)新變量,在賦值過程中就發(fā)生了拷貝,迭代的實(shí)際上是副本,這也就解釋了現(xiàn)象 1。
  2. 在循環(huán)過程中,會(huì)將迭代元素賦值給一個(gè)臨時(shí)變量,這又發(fā)生了拷貝。如果取地址的話,每次都是一樣的,都是臨時(shí)變量的地址。

以上就是本文的全部?jī)?nèi)容,如果覺得還不錯(cuò)的話歡迎點(diǎn)贊,轉(zhuǎn)發(fā)和關(guān)注,感謝支持。

參考文章:

  • https://garbagecollected.org/2017/02/22/go-range-loop-internals/
  • https://draveness.me/golang/docs/part2-foundation/ch05-keyword/golang-for-range/

網(wǎng)站題目:為什么 Go For-Range 的 value 值地址每次都一樣?
URL分享:http://www.dlmjj.cn/article/dhhpjsh.html