根据围棋的游,在围棋切片s
,表达式s[lo:hi]
的计算结果为从元件的切片lo
通过hi-1
,包括:
package main import "fmt" func main() { p := []int{0, // slice position 0 10, // slice position 1 20, // slice position 2 30, // slice position 3 40, // slice position 4 50} // slice position 5 fmt.Println(p[0:3]) // => [0 10 20] }
在我上面的代码示例中,"p [0:3]"似乎直观地"读取"为:"从位置0到位置3的切片",等于[0,10,20,30].但当然,它实际上相当于[0 10 20].
所以我的问题是:评估上限值的设计原理是什么hi-1
而不是简单hi
?这感觉不直观,但必须有一些理由让我失踪,我很好奇这可能是什么.
提前致谢.
这完全是一个惯例问题,当然还有其他方法(例如,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]) }
(这段代码显然不能很好地处理一些边缘情况,但你明白了)
如果我们尝试使用包容性包含切片来编写等效函数,那将会更加复杂.
如果有人再想一想,请随时编辑此答案并添加它们.