golang 中的 nil 切片和空切片有什么意义?

Ste*_*Ste 6 null go slice

区分 nil 切片有什么意义,即。未初始化的切片和空切片,即。已初始化但空切片?

我理解其中的差异,但我想知道这两种情况之间存在细微差异背后的动机是什么?出于所有意图和目的,nil 切片和空切片在使用时表现相同。

似乎如果 Go 开发人员只有一种情况,例如只允许空切片,它就会简化心理模型并消除细微错误的来源。

创建这两个用例是否有原因?

icz*_*cza 6

切片nil值不需要分配。如果您想要在切片中构建某些内容,但通常没有要附加的数据,因此切片可能会保留nil,因此完全不需要分配,这可能会有所不同。

空切片可能需要分配,即使其容量为零。

另外,空切片意味着其长度为 0,但其容量可能不是;因此, “无论出于何种意图和目的,nil切片和空切片在使用时的行为都相同”是不正确的。。您可以分配长度为 0 且容量较大的切片,优化进一步的附加以避免分配(和复制):

s := make([]int, 0)
fmt.Println(s, len(s), cap(s))
s = append(s, 1)
fmt.Println(s, len(s), cap(s))

s = make([]int, 0, 10)
fmt.Println(s, len(s), cap(s))
s = append(s, 1)
fmt.Println(s, len(s), cap(s))
Run Code Online (Sandbox Code Playgroud)

上面的输出(在Go Playground上尝试一下):

[] 0 0
[1] 1 2
[] 0 10
[1] 1 10
Run Code Online (Sandbox Code Playgroud)

我们看到了什么?在第一个示例中,我们创建了一个长度为 0、容量为 0 的空切片。如果我们向它追加一个元素,它的长度将变成 1(显然),并且它的容量增加到 2。这是因为在幕后append()分配了一个大小为 2 的新数组(考虑到未来的增长),复制了现有的元素(在本例中没有),并分配了新元素。

在第二种情况下,我们从一个空切片开始,但容量为 10。这意味着我们可以向其中追加 10 个元素,而不会导致新的分配和复制现有元素。当切片很大并且需要多次执行时,这可能是一个很大的优势。