为什么 go 允许从 len(slice) 切片?

Why does go allow slicing from len(slice)?

为什么会出现以下行为:

a := []int{1, 2, 3}
fmt.Println(a[0:])
fmt.Println(a[1:])
fmt.Println(a[2:])
fmt.Println(a[3:])// doesn't panic - why??
fmt.Println(a[4:])// panics as expected

Executable example

a[3:] 构建一个空切片,就像一个空数组一样,它是一个有效且有用的对象(在所有语言中,不仅仅是在 Go 中)。

空切片也仍然指向底层数组、位置和容量,有时可以扩展:

a := []int{1, 2, 3}
emptySlice := a[1:1]
fmt.Println(emptySlice) // []
notEmpty := emptySlice[0:2]
fmt.Println(notEmpty)   // [2 3]

另一端,长度为负的切片不一致。它没有任何意义,因此被禁止。

因为切片中有 0 个元素 (3-3) 是完全有效的。但是有 -1 元素 (3-4) 不是。

这种行为也与其他语言一致。例如,Java:

System.out.println(Arrays.asList(1, 2, 3).subList(0, 3));
System.out.println(Arrays.asList(1, 2, 3).subList(1, 3));
System.out.println(Arrays.asList(1, 2, 3).subList(2, 3));
System.out.println(Arrays.asList(1, 2, 3).subList(3, 3));
System.out.println(Arrays.asList(1, 2, 3).subList(4, 3));

只有最后一条语句失败了。

引自Spec: Slice Expressions

For arrays or strings, the indices are in range if 0 <= low <= high <= len(a), otherwise they are out of range. For slices, the upper index bound is the slice capacity cap(a) rather than the length.

因此规范允许使用索引最多 len(a) 的底层 array, len(a) included (或者 cap(a) 在切片的情况下,在这种情况下具有相同的值)。这就是为什么 a[3:] 在你的情况下不会恐慌。

但它当然会产生一个空切片,因为:

a[low : high]

表示结果的索引从 0 开始,长度等于 high - low 并且由于 high 被省略,因此默认为 len(a) 因此 len(a) - len(a) = 0 .

而且(根据规范)使用索引 > len(a) 将超出范围 并因此导致运行时恐慌:

If the indices are out of range at run time, a run-time panic occurs.