2 回答
TA贡献1833条经验 获得超4个赞
这完全是一个约定问题,当然还有其他方法可以做到(例如,Matlab 使用第一个索引为 1 的数组)。选择实际上取决于您想要什么属性。事实证明,使用 0 索引数组,其中切片是包含不包含的(即,从 a 到 b 的切片包含元素 a 并排除元素 b)具有一些非常好的属性,因此这是一个非常常见的选择。这里有一些优点。
0 索引数组和包含-排除切片的优点
(请注意,我使用的是非 Go 术语,所以我将以 C 或 Java 谈论它们的方式谈论数组。数组就是 Go 所说的切片,而切片是子数组(即“切片从索引 1 到索引 4"))
指针算术有效。如果您使用像 C 这样的语言,数组实际上只是指向数组中第一个元素的指针。因此,如果您使用 0 索引数组,那么您可以说索引i处的元素只是数组指针加i 所指向的元素。例如,如果我们有一个数组[3 2 1],数组的地址为10(假设每个值占用一个字节的内存),那么第一个元素的地址为10 + 0 = 10,则第二个的地址是 10 + 1 = 11,依此类推。简而言之,它使数学变得简单。
切片的长度也是切片的地方。也就是说,对于一个数组arr,arr[0:len(arr)]就是它arr本身。这在实践中非常有用。例如,如果我调用n, _ := r.Read(arr)(其中n是读入的字节数arr),那么我可以只arr[:n]获取与arr实际写入的数据对应的切片arr。
指数不重叠。这意味着如果我有arr[0:i], arr[i:j], arr[j:k], arr[k:len(arr)],这些切片完全覆盖arr自身。您可能不会经常发现自己将数组划分为这样的子切片,但它具有许多相关的优点。例如,考虑以下代码以基于非连续整数拆分数组:
func consecutiveSlices(ints []int) [][]int {
ret := make([][]int, 0)
i, j := 0, 1
for j < len(ints) {
if ints[j] != ints[j-1] + 1 {
ret = append(ret, ints[i:j])
i = j
}
}
ret = append(ret, ints[i:j])
}
(这段代码显然不能很好地处理一些边缘情况,但你明白了)
如果我们尝试使用 inclusive-inclusive 切片来编写等效的函数,它会复杂得多。
如果有人能想到更多,请随时编辑此答案并添加它们。
TA贡献1873条经验 获得超9个赞
对于字符串、数组、指向数组的指针或切片 a,主要表达式
a[low : high]构造一个子串或切片。索引 low 和 high 选择操作数 a 的哪些元素出现在结果中。结果的索引从 开始,
0
长度等于high - low
。为方便起见,可以省略任何索引。缺失的低指数默认为零;缺少的高索引默认为切片操作数的长度
对于数组或字符串,如果 0 <= low <= high <= len(a),则索引在范围内,否则它们超出范围。对于切片,索引上限是切片容量 cap(a) 而不是长度。常量索引必须是非负的并且可以用 int 类型的值表示;对于数组或常量字符串,常量索引也必须在范围内。如果两个指数都是常数,则它们必须满足 low <= high。如果索引在运行时超出范围,则会发生运行时恐慌。
对于q := p[m:n]
,q
是p
从 index 开始m
的一段n-m
元素长度的切片。
- 2 回答
- 0 关注
- 194 浏览
添加回答
举报