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

在Go切片中,为什么s[lo:hi]以元素hi-1结尾?,go,slice,Go,Slice,根据,在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

根据,在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]。当然,它实际上等于[01020]

因此,我的问题是:将上限值计算为
hi-1
而不是简单的
hi
,其设计原理是什么?这感觉不直观,但肯定有某种原因,我错过了,我很好奇这可能是什么

提前谢谢

对于字符串、数组、指向数组的指针或切片a,主 表情

a[low : high]
构造子字符串或切片。低指数和高指数选择哪一个 操作数a的元素出现在结果中。结果具有指数性 从
0
开始,长度等于
high-low

为方便起见,可省略任何索引。丢失的低点 索引默认为零;缺少的高索引默认为 切片操作数


对于数组或字符串,如果0则索引在范围内,这完全是惯例问题,当然还有其他方法可以做到这一点(例如,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])
    }
    
    func连续切片(ints[]int)[]int{
    ret:=make([]int,0)
    i、 j:=0,1
    对于j
(这段代码显然不能很好地处理某些边缘情况,但您明白了这一点)

如果我们尝试使用包含式切片来编写等效函数,它将非常复杂


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

您是否见过另一种使用包含范围的语言,其中返回的长度为
hi low+1
?我猜您问这个问题的时候好像在说:“这就是一直做的方式”?恐怕这无助于回答我的问题。不,实际上我很好奇你是否在任何地方见过它,这导致你假设在围棋中
len(s[low:hi])==hi-low+1
。对不起,我在猜测什么?我的问题直接取自围棋之旅。啊,我明白你的意思。嗯,我想这是我的一个假设,因为我对巡演中描述的行为感到惊讶。这看起来并不直观,但下面的答案帮助我理解了这种设计的原因。谢谢,但我已经参考了规范,它没有提供设计原理——这正是我所寻找的。