golang面試基礎系列-range的坑(三)

Go 中,for range 用來遍歷 slice, map, chan 等,使用頻率很高,但遍歷雖好用,卻很容易踩坑,且看 demo 以下:ui

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)
  }
}
複製代碼

輸出結果以下:spa

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)
  }
}
複製代碼

輸出結果以下:code

0xc00008e020
0xc00008e020
0xc00008e020
zhang &{wang 24}
li &{wang 24}
wang &{wang 24}
複製代碼

正確作法應該是:將 good 部分註釋打開,運行結果以下:orm

0xc00000c080
0xc00000c080
0xc00000c080
li &{li 23}
wang &{wang 24}
zhang &{zhang 22}
複製代碼

小結:for range 遍歷注意以上幾個小坑:cdn

  1. 只有一個返回值時,則第一個參數是index
  2. 遍歷 map 爲隨機序輸出,slice 爲索引序輸出;
  3. range v 是值拷貝,且只會聲明初始化一次; 掌握以上幾點後,就讓咱們愉快的使用 range 吧~

稻草人生
相關文章
相關標籤/搜索