这里有两个不同的定义,但是有什么区别? 我尝试了以下方法:
func main() {
var test1 []int
test2 := []int{}
if test1 == nil {
fmt.Println(1)
}
if test2 == nil {
fmt.Println(2)
}
fmt.Println("test1:", test1)
fmt.Println("test2:", test2)
}
这是输出:
1
test1: []
test2: []
但是为什么test1为nil但另一个不是?
答案 0 :(得分:8)
[]int
本身是int
的 slice类型的拼写。
在:
var test1 []int
[]int
提供了变量test1
的类型。整个行提供 no 值,因此test1
被初始化为类型[]int
的{{3}}。零的值为[]int(nil)
,或者非正式地为零。 1
在:
test2 := []int{}
[]int
提供了用大括号括起来的初始化程序列表的类型。也就是说,{}
是zero value:右括号,然后是元素列表(在这种情况下为空),后跟右括号。该行的其余部分(:=
和左侧的变量名称)表示composite literal。这样,变量test2
的类型 []int
以及空列表产生的值。
在这种情况下,空列表产生的值是int
的空片:其中一个空的 2 后备存储,长度为零,容量为零。
这就是test1
为零而test2
不是零的原因:test1
保持零值,对于任何切片类型,该值均为nil
(在nil
之后无论如何都会转换为该类型)。同时,test2
拥有三部分的切片标头,该标头涵盖了由复合文字创建的零长度后备数组。
nil slice-这有点草率:它表示类型为T
的slice-of类型的值,其实际值为[]T(nil)
,而不是由三部分组成的slice头-通常可以用作相同类型的空(长度为零)切片。特别是,for i := range x
和x = append(x, newElement)
都“很好”地处理x == nil
:它们对待空切片的方式相同。打印切片的fmt
例程也可以执行此操作。 3
1 nil
本身是 untyped 。请参见short variable declaration中对nil
的第一次提及。
2 至少在不使用unsafe.Pointer
或类似的情况下,不可能知道Go是否实际上为后备阵列分配了任何存储空间。您对切片执行的任何操作都会为其提供一定的容量,以便您可以将某些值放入内存中的某个位置,这将或可能只是分配一个 new 后备数组。 unsafe
软件包提供了一些技巧,可以窥探Go运行时,但总的来说,您不需要这样做,也不应该。
3 相比之下,map
类型的播放效果不太好。如果x
是(可能是非正式的)一片,可能是零,而m
是一张可能是零的地图,我们可以这样做:
x = append(x, newElem)
但我们不能这样做:
m[key] = newElem
我们必须首先检查m
是否为nil,如果是,则分配一个空映射:
if m == nil {
m = make(...) // put in the right type here
}
m[key] = newElem
因此使用是相对常见的:
var x []T
m := map[string]T{}
彼此相邻,因为x
的行为会很好,而m
的行为会不会。
答案 1 :(得分:0)
nil和空片之间的区别。在golang中,如果您声明的变量没有值,则其值将成为变量类型的零值。数组的零值为nil。不是空片。空切片可以通过make函数或shorty生成,该方法是您用于test2的第二种方法