小编典典

在Go切片中,为什么s [lo:hi]在元素hi-1处结束?

go

根据“围棋旅”,在围棋切片中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?感觉很不直观,但是我一定缺少某些原因,我很好奇这可能是什么。

提前致谢。


阅读 257

收藏
2020-07-02

共1个答案

小编典典

这完全是一个惯例,当然还有其他方法可以做到这一点(例如,Matlab使用第一个索引为1的数组)。选择实际上取决于您想要的属性。事实证明,使用0索引数组时切片是包含所有的(即,从a到b的切片包含元素a并排除元素b)具有一些非常好的属性,因此这是一个非常常见的选择。这里有一些优点。

0索引数组和包含式-排他式切片的优点

(请注意,我使用的是非Go术语,因此我将以C或Java讨论数组的方式来讨论数组。数组是Go所谓的slice,而slice是子数组(即,“
slice”从索引1到索引4“))

  • 指针算术有效。如果您使用的语言是C,数组实际上只是指向数组中第一个元素的指针。因此,如果使用0索引数组,那么可以说索引 i 处的元素就是数组指针加 i 指向的元素。例如,如果我们有数组[3 2 1],数组的地址为10(并假设每个值占用一个内存字节),则第一个元素的地址为10 + 0 = 10,则第二个地址是10 +1 = 11,依此类推。简而言之,它使数学变得简单。
  • 切片的长度也是切片的地方。也就是说,对于一个数组arrarr[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])
    

    }

(这段代码显然不能很好地处理某些极端情况,但是您知道了)

如果我们尝试使用包含式和包含式切片来编写等效函数,则它将变得更加复杂。

如果有人能想到更多,请随时编辑并添加答案。

2020-07-02