通过使用full slice notation b = a[low:high:max]
,可以获得容量比分配的切片a
小的切片。切片b
的容量为max - low
,元素存储将与a
共享(不进行复制)。 max - low
必须小于或等于cap(a)
,否则我们会感到恐慌:
a := make([]byte, 8)
b := a[:3:10]
panic: runtime error: slice bounds out of range [::10] with capacity 8
获得较小容量的切片的可能性有什么用?
我发现的唯一有用的应用程序是使用append
强制切片的副本,从而以减小的容量绕过切片的容量。
a := []int{1, 2, 3, 4, 5}
b := a[1:3:3]
fmt.Println("a:", a, "b:",b, "cap(b):", cap(b)) // -> a: [1 2 3 4 5] b: [2 3] cap(b): 2
b[0] = 6
fmt.Println("a:", a, "b:",b, "cap(b):", cap(b)) // -> a: [1 6 3 4 5] b: [6 3] cap(b): 2
b = append(b, 7) // copy slice elements and extends capacity of b
fmt.Println("a:", a, "b:",b, "cap(b):", cap(b)) // -> a: [1 6 3 4 5] b: [6 3 7] cap(b): 4
b[1] = 8
fmt.Println("a:", a, "b:",b, "cap(b):", cap(b)) // -> a: [1 6 3 4 5] b: [6 8 7] cap(b): 4
请注意,此类副本并不明显,需要注释以使其对读者可见。
另一个有用的应用程序吗?
它确实在附加上强加了一个副本,但是它的作用是[[略]。如果使用它,则可以将切片传递给一些未知的代码段,因为该代码将无法使用该切片读取或写入超出所需范围的底层数组。
通过普通切片表达式创建的切片将具有足够的容量,可以到达对其进行切片的数组或切片的末尾,因此调用方可以对其进行重新切片,使其达到对其进行访问的能力。完整的切片表达式使此操作不可能(或超出特定点也无法实现)。这不是
安全
措施。程序中的其他代码当然可以弄清楚如何使用unsafe
以一种或另一种方式在片的末尾进行读取或写入。这只是防止意外副作用的一种方法。如果要在您关心的某些数据的中间调用带有切片的函数,并且该函数可能将append
扩展到切片或以其他方式扩展切片,则使用完整切片表达式来限制容量是明智的选择。完整的切片符号使您可以限制切片的容量。这允许垃圾回收器释放后备数组的未引用部分(假设没有其他引用对象)。这可以帮助减少程序对内存的使用。另一个用途是,如果追加超出其新容量,则避免覆盖与另一个片共享的支持数组。
尽管您的示例代码是错误的。完成b := a[2:3:4]
后,b
的长度为1(3-2),容量为2
(4-2)。因此,当您写入b = append(b, 7)
时,可以将b
的长度增加到2,而不会超出其容量。因此没有副本。