來自公眾號:新世界雜貨鋪
Q1: 如果我們在遍歷陣列的同時修改陣列元素,能否得到一個永遠都不會停止的迴圈呢?
func main() {
arr := []int{1, 2, 3}
for _, v := range arr {
arr = append(arr, v)
}
fmt.Println(arr)
}
// 輸出: 1 2 3 1 2 3
上述程式碼的輸出意味著迴圈只遍歷了原始切片中的三個元素,我們遍歷切片時追加的元素不會增加回圈的執行次數, 所以迴圈最終還是停了下來
答: 對於所有的range迴圈, Go語言會在編譯期間將原切片
或者陣列
賦值給一個新的變數ha
, 在賦值的過程中就發生了拷貝, 所以我們遍歷的切片已經不是原始的切片變數了
Q2: 我們遍歷一個陣列時,如果獲取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)
}
}
// 輸出: 3 3 3
答: 遇到這種同時遍歷索引和元素的range迴圈時, go語言會額外建立一個新的v2
變數儲存切片中的元素, 迴圈中使用的這個變數v2會在每一次迭代被重新賦值而覆蓋, 在賦值時也發生了拷貝
. 因為在迴圈中返回的變數的地址都完全相同, 所以才會出現神奇的指標的現象
Q3: go語言中使用range遍歷雜湊表時, 往往都會得到不同的結果?
答: 但這並不是說明雜湊表不穩定, 這是go語言故意這樣設計的, 他在執行時為雜湊表遍歷引入不確定性, 也是告訴所有使用go語言的使用者, 程式不要依賴於雜湊表的穩定遍歷。
https://draveness.me/golang/docs/part2-foundation/ch05-keyword/golang-for-range/