成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

開發 前端
在循環開始前,會將數組或切片賦值給一個新變量,在賦值過程中就發生了拷貝,迭代的實際上是副本,這也就解釋了現象 1。

循環語句是一種常用的控制結構,在 Go 語言中,除了 for 關鍵字以外,還有一個 range 關鍵字,可以使用 for-range 

但是在使用 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. 在循環開始前,會將數組或切片賦值給一個新變量,在賦值過程中就發生了拷貝,迭代的實際上是副本,這也就解釋了現象 1。
  2. 在循環過程中,會將迭代元素賦值給一個臨時變量,這又發生了拷貝。如果取地址的話,每次都是一樣的,都是臨時變量的地址。

以上就是本文的全部內容,如果覺得還不錯的話歡迎點贊,轉發和關注,感謝支持。

參考文章:

  • https://garbagecollected.org/2017/02/22/go-range-loop-internals/
  • https://draveness.me/golang/docs/part2-foundation/ch05-keyword/golang-for-range/
責任編輯:武曉燕 來源: AlwaysBeta
相關推薦

2021-12-27 03:36:09

語言For Golang

2023-02-08 15:38:16

首席信息官IT

2021-07-12 23:53:22

Python交換變量

2014-09-22 09:27:57

Python

2025-02-21 08:48:16

Typescript內置聯合類型

2020-02-14 14:36:23

DevOps落地認知

2020-05-08 15:48:33

手機PCAndroid

2011-11-14 10:04:27

iPhone 4SiPhone 4外觀

2012-07-18 02:05:02

函數語言編程語言

2018-07-10 11:05:55

Emoji蘋果Google

2023-02-15 10:26:34

2021-02-03 08:25:47

模塊數據概率

2011-02-28 10:38:13

Windows 8

2012-03-07 17:24:10

戴爾咨詢

2012-12-20 10:17:32

IT運維

2009-06-12 15:26:02

2024-01-16 08:57:45

Spring構造器注入單元測試

2022-03-31 10:14:00

界面設計師思路框架

2020-11-12 08:30:38

Java微服務Go

2021-04-12 10:20:20

Java微服務Go
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久精品久久久 | 亚洲国产偷 | 99久久影院 | 亚洲人在线 | 午夜手机在线视频 | 国产91一区二区三区 | 91麻豆久久久 | 午夜视频在线免费观看 | 不卡的av在线 | 免费看黄色小视频 | 伊人久久在线 | 九九精品网 | 国产欧美日韩在线 | 国产精品永久免费视频 | 天天操欧美 | 成人在线视频网址 | 香蕉婷婷| 亚洲欧美综合 | 国产精品自拍视频网站 | 久久视频精品 | 精品1区 | 国产欧美日韩综合精品一区二区 | 欧美成人免费在线 | 视频一区二区在线观看 | 麻豆av免费观看 | 日本不卡一区二区三区在线观看 | 中文字幕av在线一二三区 | 亚洲精品一区二区在线观看 | 欧美精品第一页 | 国产目拍亚洲精品99久久精品 | 成人亚洲一区 | av中文字幕在线观看 | www.久久久.com | 亚洲人成人一区二区在线观看 | 操操日| 久久精品一区二区视频 | 亚洲视频国产视频 | 午夜男人视频 | 国产精品免费一区二区三区四区 | 国产色片| 久久久做 |