欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go?for-range?的?value值地址每次都一樣的原因解析

 更新時(shí)間:2023年05月01日 07:38:02   作者:AlwaysBeta  
循環(huán)語(yǔ)句是一種常用的控制結(jié)構(gòu),在?Go?語(yǔ)言中,除了?for?關(guān)鍵字以外,還有一個(gè)?range?關(guān)鍵字,可以使用?for-range?循環(huán)迭代數(shù)組、切片、字符串、map?和?channel?這些數(shù)據(jù)類(lèi)型,這篇文章主要介紹了Go?for-range?的?value值地址每次都一樣的原因解析,需要的朋友可以參考下

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

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

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

現(xiàn)象

先來(lái)看兩段很有意思的代碼:

無(wú)限循環(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í)追加的元素并沒(méi)有增加循環(huán)的執(zhí)行次數(shù),所以循環(huán)最終還是停了下來(lái)。

相同地址

第二個(gè)例子是使用 Go 語(yǔ)言經(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

上述代碼并沒(méi)有輸出 1 2 3,而是輸出 3 3 3。

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

原因

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

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

口說(shuō)無(wú)憑,具體是不是這樣,還得靠源碼說(shuō)話。

Go 編譯器會(huì)將 for-range 語(yǔ)句轉(zhuǎn)換成類(lèi)似 C 語(yǔ)言的三段式循環(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):

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

參考文章:

到此這篇關(guān)于Go for-range 的 value 值地址每次都一樣的原因解析的文章就介紹到這了,更多相關(guān)Go for-range 的 value 值地址內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • go-micro微服務(wù)domain層開(kāi)發(fā)示例詳解

    go-micro微服務(wù)domain層開(kāi)發(fā)示例詳解

    這篇文章主要為大家介紹了go-micro微服務(wù)domain層開(kāi)發(fā)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • 關(guān)于golang test緩存問(wèn)題

    關(guān)于golang test緩存問(wèn)題

    這篇文章主要介紹了關(guān)于golang test緩存問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-09-09
  • Go中并發(fā)控制的實(shí)現(xiàn)方式總結(jié)

    Go中并發(fā)控制的實(shí)現(xiàn)方式總結(jié)

    在Go實(shí)際開(kāi)發(fā)中,并發(fā)安全是老生常談的事情,在并發(fā)下,goroutine之間的存在數(shù)據(jù)資源等方面的競(jìng)爭(zhēng),為了保證數(shù)據(jù)一致性、防止死鎖等問(wèn)題的出現(xiàn),在并發(fā)中需要使用一些方式來(lái)實(shí)現(xiàn)并發(fā)控制,本文給大家總結(jié)了幾種實(shí)現(xiàn)方式,需要的朋友可以參考下
    2023-12-12
  • golang 獲取字符串長(zhǎng)度的案例

    golang 獲取字符串長(zhǎng)度的案例

    這篇文章主要介紹了golang 獲取字符串長(zhǎng)度的案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • Go+Redis實(shí)現(xiàn)常見(jiàn)限流算法的示例代碼

    Go+Redis實(shí)現(xiàn)常見(jiàn)限流算法的示例代碼

    限流是項(xiàng)目中經(jīng)常需要使用到的一種工具,一般用于限制用戶(hù)的請(qǐng)求的頻率,也可以避免瞬間流量過(guò)大導(dǎo)致系統(tǒng)崩潰,或者穩(wěn)定消息處理速率。這篇文章主要是使用Go+Redis實(shí)現(xiàn)常見(jiàn)的限流算法,需要的可以參考一下
    2023-04-04
  • 數(shù)據(jù)競(jìng)爭(zhēng)和內(nèi)存重分配Golang slice并發(fā)不安全問(wèn)題解決

    數(shù)據(jù)競(jìng)爭(zhēng)和內(nèi)存重分配Golang slice并發(fā)不安全問(wèn)題解決

    這篇文章主要為大家介紹了數(shù)據(jù)競(jìng)爭(zhēng)和內(nèi)存重分配Golang slice并發(fā)不安全問(wèn)題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • go?goth封裝第三方認(rèn)證庫(kù)示例詳解

    go?goth封裝第三方認(rèn)證庫(kù)示例詳解

    這篇文章主要為大家介紹了go?goth封裝第三方認(rèn)證庫(kù)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • golang類(lèi)型推斷與隱式類(lèi)型轉(zhuǎn)換

    golang類(lèi)型推斷與隱式類(lèi)型轉(zhuǎn)換

    這篇文章主要介紹了golang類(lèi)型推斷與隱式類(lèi)型轉(zhuǎn)換,golang類(lèi)型推斷可以省略類(lèi)型,像寫(xiě)動(dòng)態(tài)語(yǔ)言代碼一樣,讓編程變得更加簡(jiǎn)單,同時(shí)也保留了靜態(tài)類(lèi)型的安全性
    2022-06-06
  • Golang::slice和nil的對(duì)比分析

    Golang::slice和nil的對(duì)比分析

    這篇文章主要介紹了Golang::slice和nil的對(duì)比分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • Golang導(dǎo)入包的幾種方式(點(diǎn),別名與下劃線)

    Golang導(dǎo)入包的幾種方式(點(diǎn),別名與下劃線)

    這篇文章主要介紹了Golang導(dǎo)入包的幾種方式(點(diǎn),別名與下劃線),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02

最新評(píng)論