Arrays Go Slice-[:n]和[n:]之间的差异

Arrays Go Slice-[:n]和[n:]之间的差异,arrays,go,slice,Arrays,Go,Slice,去切片的问题,请检查下面,并评论,如果我遗漏了什么 import "fmt" func main() { s := []int{2, 3, 5, 7, 11, 13} s = s[1:] fmt.Println(s) s = s[2:] fmt.Println(s) s = s[5:] fmt.Println(s) } 输出: [3 5 7 11 13] [7 11 13] 恐慌:

去切片的问题,请检查下面,并评论,如果我遗漏了什么

   import "fmt"
   func main() {
       s := []int{2, 3, 5, 7, 11, 13}
       s = s[1:]
       fmt.Println(s)
       s = s[2:]
       fmt.Println(s)
       s = s[5:]
       fmt.Println(s)
  }
输出:

[3 5 7 11 13]
[7 11 13]
恐慌:运行时错误:切片边界超出范围

上述观点是有道理的

func main() {
       s := []int{2, 3, 5, 7, 11, 13}
       s = s[:1]
       fmt.Println(s)
       s = s[:2]
       fmt.Println(s)
       s = s[:5]
       fmt.Println(s)
   }
输出:

[2]
[2 3]
[2 3 5 7 11]


这是否也会使阵列超出s=s[:2]的边界恐慌?

Go中的子扫描允许您在片的末端进行切片,只要它仍在基线阵列的容量范围内。您不能在片段开始之前进行切片,但只要不超过最后分配的索引,就可以在片段开始之后进行切片

例如,
s[3://code>然后
s[:3]
可以工作,但是
s[4://code>然后
s[:4]
将死机,因为您请求的是底层数组的索引4到7,该数组只分配了索引0-5

这有点奇怪,但它确实允许您通过执行
slice=slice[:cap(slice)]
来最大化任何切片

顺便说一句,注释说明了这一点。我在下面对您使用的简单切片表示法进行了解释(还有一种替代方法,它还指定了新切片的最大索引)

对于字符串、数组、指向数组的指针或切片,主表达式
a[low:high]
构造一个子字符串或切片。
如果0Go中的子扫描允许您在切片结束后进行切片,只要它仍在基线阵列容量的范围内,则索引在范围内。您不能在片段开始之前进行切片,但只要不超过最后分配的索引,就可以在片段开始之后进行切片

例如,
s[3://code>然后
s[:3]
可以工作,但是
s[4://code>然后
s[:4]
将死机,因为您请求的是底层数组的索引4到7,该数组只分配了索引0-5

这有点奇怪,但它确实允许您通过执行
slice=slice[:cap(slice)]
来最大化任何切片

顺便说一句,注释说明了这一点。我在下面对您使用的简单切片表示法进行了解释(还有一种替代方法,它还指定了新切片的最大索引)

对于字符串、数组、指向数组的指针或切片,主表达式
a[low:high]
构造一个子字符串或切片。
如果指数在0范围内,我只是想在阅读官方博客后分享我的想法:

以下是Golang博客中的标题:

type sliceHeader struct {
    Length        int
    ZerothElement *byte
}
现在声明您的切片:

s := []int{2, 3, 5, 7, 11, 13}
我相信它的作用是:

var array [6]int
slice := sliceHeader {
    Length:        6,
    ZerothElement: &array[0], 
}
通过执行:
s=s[:2]
,您有效地将切片头的长度从6更改为2,因此切片头将如下所示:

slice := sliceHeader {
    Length:        2,
    ZerothElement: &array[0],
}
请注意,zerothement仍然指向内存中的相同位置。因此,只需再次更改长度,我们就可以将切片扩展回其原始形式
s=s[:6]

现在,假设您没有执行
s=s[:2]
,而是执行了
s=s[2:]
,您实际执行的是通过从长度中减去2并向前移动Zerothement两个索引来隐藏前两个元素,从而产生一个切片头:

slice := sliceHeader {
    Length:        4,
    ZerothElement: &array[2],   
}
此时,您无法将切片恢复为其原始形式,因为无法将切片扩展到zerothement之外。好吧,假设你可以访问零点之前的任何元素呢?然后,我们的切片变得未定义,因为它可能是
数组[0…4]
数组[1…5]
,或
数组[2…6]


所以是的,这就是为什么我认为[n:]和[:n]的行为不同。

我只是想在阅读官方博客后分享我的想法:

以下是Golang博客中的标题:

type sliceHeader struct {
    Length        int
    ZerothElement *byte
}
现在声明您的切片:

s := []int{2, 3, 5, 7, 11, 13}
我相信它的作用是:

var array [6]int
slice := sliceHeader {
    Length:        6,
    ZerothElement: &array[0], 
}
通过执行:
s=s[:2]
,您有效地将切片头的长度从6更改为2,因此切片头将如下所示:

slice := sliceHeader {
    Length:        2,
    ZerothElement: &array[0],
}
请注意,zerothement仍然指向内存中的相同位置。因此,只需再次更改长度,我们就可以将切片扩展回其原始形式
s=s[:6]

现在,假设您没有执行
s=s[:2]
,而是执行了
s=s[2:]
,您实际执行的是通过从长度中减去2并向前移动Zerothement两个索引来隐藏前两个元素,从而产生一个切片头:

slice := sliceHeader {
    Length:        4,
    ZerothElement: &array[2],   
}
此时,您无法将切片恢复为其原始形式,因为无法将切片扩展到zerothement之外。好吧,假设你可以访问零点之前的任何元素呢?然后,我们的切片变得未定义,因为它可能是
数组[0…4]
数组[1…5]
,或
数组[2…6]


是的,这就是为什么我认为[n:]和[:n]的行为不同。

谢谢,我的问题是w.r.t赋值,当我们做s=s[:n]时,我的想法是s被新的片覆盖,而旧数组中的\slice实际上丢失了。对我来说这似乎有点不直观。啊,不,相同的底层数组。从根本上说,切片只是一个3字结构,具有指向底层数组的指针、整数长度和整数容量。当您进行子切片时,您可以根据需要使用更新的字段更改切片“头”(或创建一个新的头)。执行
s=s[:n]
时,所做的只是将切片头的“长度”值更改为
n
。仍然指向相同的基础阵列,仍然具有相同的容量,因此您可以再次将其扩展到该容量。如果您要制作基础阵列的副本(即,有一个新的切片指向完全不同的阵列,但其中包含相同的数据),则需要手动执行,逐个索引,或使用内置函数,它做切片的深度复制。编辑:仅深度复制到阵列级别。如果您的数组存储点