golang面试基础系列-range的坑(三)

作者: 热爱coding的稻草 | 来源:发表于2019-07-21 20:00 被阅读13次

    Go 中,for range 用来遍历 slice, map, chan 等,使用频率很高,但遍历虽好用,却很容易踩坑,且看 demo 如下:

    1. 只有一个返回值时,则第一个参数是 index

    package main
    
    import "fmt"
    
    func main() {
      s := []string{"a", "b", "c"}
    
      // 只有一个返回值:则第一个参数是index
      for v := range s {
        fmt.Println(v)
      }
    
      // 两个返回值
      for i, v := range s {
        fmt.Println(i, v)
      }
    }
    

    输出结果如下:

    0
    1
    2
    =============
    0 a
    1 b
    2 c
    

    2. 遍历 map 为随机序输出,slice 为索引序输出

    package main
    
    import "fmt"
    
    func main() {
      m := make(map[string]string)
    
      m["aaa"] = "AAA"
      m["bbb"] = "BBB"
      m["ccc"] = "CCC"
      m["ddd"] = "DDD"
      m["eee"] = "EEE"
    
      // range map 为随机序输出
      for i, v := range m {
        fmt.Println(i, v)
      }
    
      fmt.Println("==================")
    
      s := []string{"aaa", "bbb", "ccc", "ddd", "eee"}
      
      // range slice 为索引序输出
      for i, v := range s {
        fmt.Println(i, v)
      }
    }
    

    输出结果如下:

    
    ddd DDD
    eee EEE
    aaa AAA
    bbb BBB
    ccc CCC
    ==================
    0 aaa
    1 bbb
    2 ccc
    3 ddd
    4 eee
    

    3. range v 是值拷贝,且只会声明初始化一次

    package main
    
    import "fmt"
    
    func main() {
      ParseStudent()
    }
    
    type student struct {
      Name string
      Age  int
    }
    
    func ParseStudent() {
      m := make(map[string]*student)
      stus := []student{
        {Name: "zhang", Age: 22},
        {Name: "li", Age: 23},
        {Name: "wang", Age: 24},
      }
      for _, stu := range stus {
        // 都指向了同一个stu的内存指针,为什么?
        // 因为 for range 中的 v 只会声明初始化一次
        // 不会每次循环都初始化,最后赋值会覆盖前面的
    
        fmt.Printf("%p\n", &stu)
    
        // 1. bad
        m[stu.Name] = &stu
    
        // 2. good
        /*newStu := stu
        m[stu.Name] = &newStu*/
      }
    
      for i, v := range m {
        fmt.Println(i, v)
      }
    }
    

    输出结果如下:

    0xc00008e020
    0xc00008e020
    0xc00008e020
    zhang &{wang 24}
    li &{wang 24}
    wang &{wang 24}
    

    正确做法应该是:将 good 部分注释打开,运行结果如下:

    0xc00000c080
    0xc00000c080
    0xc00000c080
    li &{li 23}
    wang &{wang 24}
    zhang &{zhang 22}
    

    小结:for range 遍历注意以上几个小坑:

    1. 只有一个返回值时,则第一个参数是index
    2. 遍历 map 为随机序输出,slice 为索引序输出;
    3. range v 是值拷贝,且只会声明初始化一次;
      掌握以上几点后,就让我们愉快的使用 range 吧~
    稻草人生

    相关文章

      网友评论

        本文标题:golang面试基础系列-range的坑(三)

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