为什么Go语言允许从len(slice)进行切片操作?

huangapple go评论76阅读模式
英文:

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:])// 为什么不会引发错误??
fmt.Println(a[4:])// 如预期一样引发错误

可执行示例:链接

英文:

Why does the following behavior occur:

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

答案1

得分: 6

规范:切片表达式中引用:

对于数组或字符串,如果 0 <= low <= high <= len(a),则索引处于范围内,否则索引处于范围外。对于切片,上限索引是切片容量 cap(a),而不是长度。

因此,规范允许使用索引直到底层数组的 len(a),包括 len(a)(或者在切片的情况下是 cap(a),在这种情况下它们具有相同的值)。这就是为什么在你的情况下 a[3:] 不会引发错误。

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

a[low : high]

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

而且(根据规范),使用索引 > len(a) 将会超出范围,从而导致运行时错误:

如果索引在运行时超出范围,将会发生运行时错误。

英文:

Quoting from the Spec: Slice Expressions:

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

So the specification allows to use indices up to len(a) of the underlying array, len(a) included (or cap(a) in case of a slice which in this case has the same value). That's why a[3:] in your case doesn't panic.

But it will yield an empty slice of course, because:

a[low : high]

means the result has indices starting at 0 and length equal to high - low and since high is omitted, it defaults to len(a) therefore len(a) - len(a) = 0.

And also (according to the spec) using an index &gt; len(a) will be out of range and therefore cause a runtime panic:

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

答案2

得分: 3

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

空切片仍然指向一个底层数组,具有一个位置和一个容量,并且有时可以进行扩展:

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

另一方面,具有负长度的切片是不一致的。它表示无意义,因此是被禁止的。

英文:

a[3:] builds an empty slice which, just like an empty array, is a valid and useful object (in all languages, not just in Go).

An empty slice also still points to an underlying array, a position and a capacity and can sometimes be extended:

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

On the other end, a slice with a negative length is inconsistent. It means nothing and thus is forbidden.

答案3

得分: 2

因为在切片中有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));

只有最后一条语句失败。

英文:

Because having 0 elements (3-3) in the slice is perfectly valid. However having -1 element (3-4) is not.

Such behavior is also consistent with other languages. For example, 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));

Only the last statement fails.

huangapple
  • 本文由 发表于 2015年5月13日 15:19:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/30208182.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定