1. 前言
我们在了解了slice的源码之后得知,它的底层有三个属性,第一个是指向底层数组的指针,第二个是slice的长度,第三个是slice的容量。那当我们定义一个slice的变量的时候,如果给它初始化值是Nil,会发生什么?
2. 实战
先来看看一个例子:
package main import ( "fmt" ) func main() { a := []string{"A", "B", "C", "D", "E"} a = nil fmt.Println(a, len(a), cap(a)) }
结果:
[] 0 0
说明a是一个Nil的slice,它的长度和容量都是0。
但是当我们用for range
去遍历值为Nil的slice的时候会出现什么问题呢?
再来看一个例子:
package main import ( "fmt" ) func main() { a := []string{"A", "B", "C", "D", "E"} a = nil fmt.Println(a, len(a), cap(a)) for i, j := range a { fmt.Println(i, j) } }
结果:
[] 0 0
我们看到结果没有变,也没有报错,for range
到底做了什么才能在遍历值为Nil的slice的时候不报错呢?
答案就在for range
遍历slice的源码中,且看:
编译器对for range的处理流程如下: for_temp := range len_temp := len(for_temp) for index_temp := 0; index_temp < len_temp; index_temp++ { value_temp = for_temp[index_temp] index = index_temp value = value_temp origin body }
从源码中可以看出,它先得到slice的长度,值为Nil的长度当然是0,所以在for循环遍历的时候,因为长度不满足遍历条件,所以进不去循环,这就证明了值为Nil的切片在for range
遍历的时候是没有问题的。
3. 小结
针对slice的特例我们一定要牢记,因为在项目中会大量使用,而且slice的变量是引用传递,所以在使用之前最好有Nil的断言,否则在传递的过程中无法保证被谁赋值为Nil从而导致程序奔溃。