> 文章列表 > golang for range 令人抓狂的面试题

golang for range 令人抓狂的面试题

golang for range 令人抓狂的面试题

1.下面这段代码能否正常结束?

func main() {v := []int{1, 2, 3}for i := range v {v = append(v, i)}
}

 答案:正常结束。    可能我们会以为程序会陷入死循环。 但是我们要明白 for range  中的v其实就是复制了一份前面定义的v切片,不论前面定义的v如何变化,range中的v长度不会变化。所以只会循环三次。我们可以把range中的v看做是一个新变量,只是这个变量复制了一份v的数据。

2.根据第一题,v最终打印出来是什么样的呢?

func main() {v := []int{1, 2, 3}for i := range v {v = append(v, i)}fmt.Println(v)
}

答案:[1 2 3 0 1 2]

3.如果我们把第二题再变化一下,看看如下v会有什么变化,注意 变化在 v := append(v,i)   =  与 :=

func main() {v := []int{1, 2, 3}for i := range v {v := append(v, i)fmt.Println("循环中", v)}fmt.Println("最后:", v)
}

答案:输出结果

v最终的结果没有改变,因为 v :=  append(v,i)  v是一个新的变量,不是前面声明的v,所以不影响前面的v数据。

 4.下面这段代码输出什么?为什么?

func main() {var m = [...]int{1, 2, 3}for i, v := range m {go func() {fmt.Println(i, v)}()}time.Sleep(time.Second * 3)
}

答案:

for range 使用短变量声明(:=)的形式迭代变量,需要注意的是,变量 i、v 在每次循环体中都会被重用,而不是重新声明。

各个 goroutine 中输出的 i、v 值都是 for range 循环结束后的 i、v 最终值,而不是各个goroutine启动时的i, v值。可以理解为闭包引用,使用的是上下文环境的值。

如果要在携程中得到每个循环当前的值,需要做如下的改动才行:

 

5.下面这段代码输出什么?

func main() {var a = [5]int{1, 2, 3, 4, 5}var r [5]intfor i, v := range a {if i == 0 {a[1] = 12a[2] = 13}r[i] = v}fmt.Println("r = ", r)fmt.Println("a = ", a)
}

答案:

 range中的a就是复制了上面定义的a数组的数据(注意上面定义的是数组不是切片),所以在循环的时候 i,v 得到的就是复制a的各元素数据, 而  if判断中 有修改 前面定义数组a的数据,所以a的数据有变化。

6.将第五题做下变化,如下(range中的是 &a )

func main() {var a = [5]int{1, 2, 3, 4, 5}var r [5]intfor i, v := range &a {if i == 0 {a[1] = 12a[2] = 13}r[i] = v}fmt.Println("r = ", r)fmt.Println("a = ", a)
}

 答案:

 以为range中的&a 是指针变量,虽然是复制的a变量,但指向的是a数组的内存,所以a与&a底层数据都同一份,当有改变时,range里的数据也会改变,所以最终r与a都是一样。

7.如果第五题中,a不是数组而是切片呢,那结果又如何?

func main() {var a = []int{1, 2, 3, 4, 5}var r [5]intfor i, v := range a {if i == 0 {a[1] = 12a[2] = 13}r[i] = v}fmt.Println("r = ", r)fmt.Println("a = ", a)
}

答案:

 因为a是切片,切片是值引用, 那么range中的a虽然是复制的前面的a,但是底层都是指向同一个内存。所以a的变化,range中的也会变化。

8.下面这段代码输出什么结果?

type Foo struct {bar string
}
func main() {s1 := []Foo{{"A"},{"B"},{"C"},}s2 := make([]*Foo, len(s1))for i, value := range s1 {s2[i] = &value}fmt.Println(s1[0], s1[1], s1[2])fmt.Println(s2[0], s2[1], s2[2])
}

答案:

 for range 使用短变量声明(:=)的形式迭代变量时,变量 i、value 在每次循环体中都会被重用,而不是重新声明。 &value指向的 就是range中不断变化的 value,所以,s2每个元素的值是循环最后的vlaue值。