go - 在 Go slice 中,为什么 s[lo :hi] end at element hi-1?

标签 go slice

根据Tour of Go ,在 Go slice s 中,表达式 s[lo:hi] 求值为从 lohi 的元素 slice -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 的 slice ”,等于 [0, 10, 20, 30]。但当然,它实际上等于 [0 10 20]。

所以我的问题是:将上限值评估为 hi-1 而不仅仅是 hi 的设计原理是什么?感觉不直观,但我想念它一定是有原因的,我很好奇这可能是什么。

提前致谢。

最佳答案

这完全是一个约定俗成的问题,当然还有其他方法可以做到(例如,Matlab 使用第一个索引为 1 的数组)。选择实际上取决于您想要什么属性。事实证明,使用 0-indexed 数组,其中 slice 是独占的(即,从 a 到 b 的 slice 包括元素 a 并排除元素 b)具有一些非常好的属性,因此它是一个非常常见的选择。这里有一些优点。

0索引数组和包容-独占 slice 的优势

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

  • 指针算术有效。如果您使用像 C 这样的语言,那么数组实际上只是指向数组中第一个元素的指针。因此,如果您使用索引为 0 的数组,那么您可以说索引 i 处的元素只是数组指针所指向的元素加上 i。例如,如果我们有数组 [3 2 1],数组的地址是 10(假设每个值占用一个字节的内存),那么第一个元素的地址是 10 + 0 = 10,则第二个的地址是 10 + 1 = 11,依此类推。简而言之,它使数学变得简单。
  • slice 的长度也是 slice 的地方。也就是说,对于数组 arrarr[0:len(arr)] 只是 arr 本身。这在实践中非常有用。例如,如果我调用 n, _ := r.Read(arr)(其中 n 是读入 arr 的字节数) ,那么我可以只做 arr[:n] 来获取与实际写入 arr 的数据相对应的 arr slice 。
  • 指数不重叠。这意味着如果我有 arr[0:i], arr[i:j], arr[j:k], arr[k:len(arr)],这些 slice 完全覆盖了 arr 本身。您可能不会经常发现自己像这样将数组划分为子 slice ,但它有许多相关的优点。例如,考虑以下代码,根据不连续的整数拆分数组:

    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 slice 来编写等效函数,那会明显更复杂。

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

关于go - 在 Go slice 中,为什么 s[lo :hi] end at element hi-1?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26857582/

相关文章:

arrays - 已知长度数据的 slice 与数组

python - OpenCV python : cv2. split() vs 在 BGR 图像中获取 channel 时进行切片

go - Golang-使用PuerkitoBio/goquery分别为每个子元素查找文本

Golang 惯用的错误处理

mongodb - 选择功能不能只获取我想要的数组

pointers - 在映射中的结构上调用指针方法

go - 如何在使用 gorm 插入时跳过结构中的特定字段

reflection - 在 Go 中使用反射设置 slice 索引

pointers - 在 Go 中使用 unsafe.Pointer 引起 panic

string - 戈朗 : print string array in an unique way