在 Go 中,for range會針對範圍運算式產生的值,重複執行一段程式區塊。
範圍運算式決定了每次疊代會產生一個值還是兩個值。
對切片使用range會依序產生每個元素的索引與值:
vals := []int{10, 20, 30}
for i, v := range vals {
fmt.Println(i, v)
}
// 0 10
// 1 20
// 2 30
對映射使用range會產生每個鍵與值,但疊代順序沒有保證。
Go 刻意將映射的疊代順序隨機化,因此同一個程式每次執行可能產生不同的輸出。
hash := map[int]int{9: 10, 99: 20, 999: 30}
for k, v := range hash {
fmt.Println(k, v)
}
// 99 20
// 999 30
// 9 10
對字串使用range會產生位元組索引與每個 rune(Unicode 碼點)。
在下面的例子中,子佔用三個位元組,所以猫從位元組索引3開始,而不是1。
for i, r := range "子猫" {
fmt.Println(i, r, string(r))
}
// 0 23376 子
// 3 29483 猫
如果你需要的是 rune 索引,請把字串轉成 rune 的切片:
for i, r := range []rune("子猫") {
fmt.Println(i, r, string(r))
}
// 0 23376 子
// 1 29483 猫
range可以直接疊代整數,產生從0開始、到該整數之前(不含該整數)的值。
零與負數是有效的,但不會產生任何疊代。
for n := range 3 {
fmt.Println(n)
}
// 0
// 1
// 2
range接受型別為iter.Seq[V]或iter.Seq2[K, V]的疊代器。
疊代器是一個函式,會一次產生一個值。
range接著可以逐一走過這些值。
text := "The quick brown fox"
for word := range strings.FieldsSeq(text) {
fmt.Println(word)
}
// The
// quick
// brown
// fox
names := []string{"Alice", "Bob", "Vera"}
for i, v := range slices.All(names) {
fmt.Println(i, ":", v)
}
// 0 : Alice
// 1 : Bob
// 2 : Vera
最後,range可以接收透過通道送來的值,直到該通道在別處被關閉為止。
通道會在後續的課程大綱中有更深入的介紹。
如果有變數被宣告卻從未使用,Go 就不會完成編譯。
vals := []int{10, 20, 30}
for i, v := range vals {
fmt.Println(v)
}
// Go build failed: declared and not used: i
如果只需要值,就把索引或鍵指定給_來忽略它。
vals := []int{10, 20, 30}
for _, v := range vals {
fmt.Println(v)
}
// 10
// 20
// 30
如果只需要索引,就完全省略它:
vals := []int{10, 20, 30}
for i := range vals {
fmt.Println(i)
}
// 0
// 1
// 2
如果索引和值都不需要,兩者都可以省略:
vals := []int{10, 20, 30}
count := 0
for range vals {
count++
}
// count == 3