天天看點

Golang入門專題-Range疊代器

Range

range周遊各種資料結構中的元素,本質上是Go内置的疊代器。

package main

import "fmt"

func main() {
    // 疊代一個slice,對元素求和
    nums := []int{2, 3, 4}
    sum := 0
    // range函數有傳回值,如果是疊代slice,則傳回index和value
    for _, num := range nums {
        sum += num
    }
    fmt.Println("sum:", sum)

    for i, num := range nums {
        if num == 3 {
            fmt.Println("index:", i)
        }
    }

    // 疊代map,則傳回key和value
    kvs := map[string]string{"a": "apple", "b": "banana"}
    for k, v := range kvs {
        fmt.Printf("%s -> %s\n", k, v)
    }

    // 僅疊代map的keys,傳回key
    for k := range kvs {
        fmt.Println("key:", k)
    }
  
    // 疊代字元串,傳回char的index和char對應的字元編碼
    // g的ascii碼為103,o的ascii碼為111
    for i, c := range "go" {
        fmt.Println(i, c)
        // 還原為字元串
        fmt.Println(i, string(c))
    }
}           

上面程式的輸出:

$ go run range.go
sum: 9
index: 1
a -> apple
b -> banana
key: a
key: b
0 103
1 111           

周遊通道

對于通道來說,range 會一直阻塞直到通道關閉,每次疊代傳回通道中的下一個值。

ch := make(chan int)
go func() {
    ch <- 1
    ch <- 2
    ch <- 3
    close(ch)
}()
for v := range ch {
    fmt.Println(v)
}           

上面程式的輸出:

1
2
3           

忽略傳回值

有時候我們隻需要周遊數組、切片、字元串、映射或通道中的值,而不需要用到下标或鍵。這時候可以使用空白辨別符 _ 來忽略下标或鍵。

s := []int{1, 2, 3}
for _, v := range s {
    fmt.Println(v)
}

m := map[string]int{"foo": 1, "bar": 2, "baz": 3}
for k := range m {
    fmt.Println(k)
}

ch := make(chan int)
go func() {
    ch <- 1
    ch <- 2
    ch <- 3
    close(ch)
}()
for range ch {
    fmt.Println("received from channel")
}           

上面程式的輸出:

1

2

3

foo

bar

baz

received from channel

received from channel

received from channel

在這個例子中,我們使用空白辨別符 _ 來忽略了數組、切片、字元串、映射和通道中的下标或鍵。

跳出疊代

在循環中,可以使用 break 關鍵字來跳出循環,或使用 continue 關鍵字來跳過目前疊代。

s := []int{1, 2, 3, 4, 5}
for _, v := range s {
    if v == 3 {
        break
    }
    fmt.Println(v)
}

m := map[string]int{"foo": 1, "bar": 2, "baz": 3}
for k, v := range m {
    if k == "bar" {
        continue
    }
    fmt.Println(k, v)
}           

上面程式的輸出:

1

2

foo 1

baz 3

在這個例子中,我們使用 break 來在數組、切片、字元串、映射和通道中跳出循環,或使用 continue 來跳過目前疊代。

多元數組

如果需要周遊多元數組或切片,可以使用多個 range。每個 range 對應一個次元。

arr := [2][3]int{{1, 2, 3}, {4, 5, 6}}
for _, row := range arr {
    for _, v := range row {
        fmt.Println(v)
    }
}

s := [][]int{{1, 2}, {3, 4, 5}, {6, 7, 8, 9}}
for _, row := range s {
    for _, v := range row {
        fmt.Println(v)
    }
}           

每日一Tip

需要注意的是,對于映射來說,range 的疊代順序是随機的。如果需要按照特定順序疊代映射的鍵或值,可以将其存儲到一個切片中,然後對切片進行排序或者自定義排序函數。