golang for range 2022-08-31

2022-08-31  本文已影响0人  9_SooHyun

核心结论:for range遍历的是拷贝的对象,不是原对象

for range 会拷贝遍历的对象,然后遍历这个拷贝的新对象

for range map:

// ###for range map###
// You can edit this code!
// Click here and start typing.
package main

import "fmt"

func main() {

    var m1 = make(map[int]int)
    m1[1] = 1
    m1[2] = 2
    m1[3] = 3

    // 可以正常删除当前访问的k v,不影响对map的完整遍历
    for key, val := range m1 {
        fmt.Println(key, val)
        delete(m1, key)
    }
    fmt.Println("final map len: ", len(m1)) // 0

    // for range 内部对map新增k v或者删除k v
    // 新增的k v不一定能被遍历到,因为可能这对kv插入了已经iter过的bucket中
    var m = map[int]int{1: 1, 2: 2, 3: 3}
    for i, _ := range m {
        m[i+3] = i + 3
        fmt.Printf("%d%d ", i, m[i])
    }

}

for range slice1:

// ###for range slice1###
// You can edit this code!
// Click here and start typing.
package main

import "fmt"

func main() {
    // for range s 会拷贝 s 得到s',而 len(s') = 3
    // ele是遍历s'得到的,遍历发生在s'上,因此即使在for range内不断对s append也不会产生无限循环
    s := []int{1, 2, 3}
    for _, ele := range s {
        fmt.Println(ele)
        s = append(s, ele+3)
    }
    fmt.Println(s) // [1 2 3 4 5 6]
}

// 1
// 2
// 3
// [1 2 3 4 5 6]

for range slice2:

// ###for range slice2###
// You can edit this code!
// Click here and start typing.
package main

import "fmt"

func main() {
    // for range s 会拷贝 s 得到s',而 len(s‘) = 5
    // range的对象实际上是s的一份拷贝s',s'和s共同引用一个底层数组
    // 因此即使在for range中对s不断截断,但是s'仍然引用了底层数组的{1, 2, 3, 4, 5}部分
    s := []int{1, 2, 3, 4, 5}
    for _, ele := range s {
        s = s[:len(s)-1] // 截断s
        fmt.Println("current s:", s)
        fmt.Println("visited ele:", ele)
        fmt.Println("---")

    }

}

// current s: [1 2 3 4]
// visited ele: 1
// ---
// current s: [1 2 3]
// visited ele: 2
// ---
// current s: [1 2]
// visited ele: 3
// ---
// current s: [1]
// visited ele: 4
// ---
// current s: []
// visited ele: 5
// ---

// ###for range slice###
// You can edit this code!
// Click here and start typing.
package main

import "fmt"

func main() {
    // for range s 会拷贝 s 得到s',而 len(s') = 5
    // range的对象实际上是s的一份拷贝s',s'和s是两个独立的数组,不会相互影响
    // 因此即使在for range中对s进行修改,但s'的值不会被影响,遍历得到的仍然是1 2 3 4 5
    s := [5]int{1, 2, 3, 4, 5}
    for index, ele := range s {
        if index < 4 {
            s[index+1] = 100 + s[index]
        }

        fmt.Println("original s:", s)
        fmt.Printf("visited range index: %d, visited range ele: %d\n", index, ele)
        fmt.Println("---")

    }

}

// original s: [1 101 3 4 5]
// visited range index: 0, visited range ele: 1
// ---
// original s: [1 101 201 4 5]
// visited range index: 1, visited range ele: 2
// ---
// original s: [1 101 201 301 5]
// visited range index: 2, visited range ele: 3
// ---
// original s: [1 101 201 301 401]
// visited range index: 3, visited range ele: 4
// ---
// original s: [1 101 201 301 401]
// visited range index: 4, visited range ele: 5
// ---

核心结论:for range遍历的是拷贝的对象,不是原对象

上一篇 下一篇

猜你喜欢

热点阅读