美文网首页
golang for range 2022-08-31

golang for range 2022-08-31

作者: 9_SooHyun | 来源:发表于2022-08-31 10:20 被阅读0次

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

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

    • for range 引用型对象
      map, slice本身是引用型的对象,for range拷贝的就当然只是引用,或者说header。在for range中对map, slice的原对象进行修改,有可能对遍历的结果产生影响,因为原对象和拷贝的、被遍历的对象,指向同一份底层数据

    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 值型对象
      array是值类型的对象,for range会进行值拷贝。在for range中对array原对象进行修改,不会对遍历的结果产生影响,因为原对象和拷贝的、被遍历的对象,是两个独立的对象
    // ###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遍历的是拷贝的对象,不是原对象

    相关文章

      网友评论

          本文标题:golang for range 2022-08-31

          本文链接:https://www.haomeiwen.com/subject/ijvdnrtx.html