Go中的切片如何不获得解引用?

Go中的切片如何不获得解引用?,go,slice,Go,Slice,我已将问题作为注释包含在代码中 我在这里看到了矛盾。我们在这里做3片。在第一个切片s=s[:0]之后,s应始终指向s[:0] package main import "fmt" func main() { s := []int{2, 3, 5, 7, 11, 13} printSlice(s) // Slice the slice to give it zero length. //1 s = s[:0] printSlice(s) //af

我已将问题作为注释包含在代码中

我在这里看到了矛盾。我们在这里做3片。在第一个切片s=s[:0]之后,s应始终指向s[:0]

package main

import "fmt"

func main() {
    s := []int{2, 3, 5, 7, 11, 13}
    printSlice(s)

    // Slice the slice to give it zero length.
    //1
    s = s[:0]
    printSlice(s) //after we do this, should not the var s always point to s[:0]?

    // Extend its length.
    s = s[:4]
    printSlice(s) //here, how is this s pointing back to original s? we just changed it to be s = s[:0]

    // Drop its first two values.
    s = s[2:]     //yet here we somehow refer to only the portion from s[:4]
    printSlice(s)  
}

func printSlice(s []int) {
    fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}
输出:

len=6 cap=6 [2 3 5 7 11 13]
len=0 cap=6 []         // slice s[:0]  
len=4 cap=6 [2 3 5 7]  // slice s[:4] - here we refer to the whole array s
len=2 cap=4 [5 7]      // slice s[2:] - here we refer not to the whole array s, but to the part we got from s[:4], which is contradiction to s[:0]

希望不要太混乱

切片是底层数组的视图。不管您如何对它进行切片,它仍然是相同的底层数组。如果取同一数组的两个切片,它们也将具有相同的底层数组,例如:

[qux]

这一点在Go博客文章中用大量的例子进行了详细解释:

切片是数组段的描述符。它由指向数组的指针、段的长度及其容量(段的最大长度)组成


因此,您可以继续使用不同的长度/容量/开始索引制作不同的切片,但使用相同的数组。它们只是同一数组上的不同视图。

一个切片有三个部分:指向底层数组的指针、长度(从指针开始)此切片中有多少个元素,以及容量(从指针开始)底层数组中有多少个元素是有效存储

当您重新切片一个切片时,指针将继续是指向同一数组的指针,长度将是您要求的长度,但不超过容量,并且容量将根据需要减少,以便新切片的地址不能超过旧切片在通常情况下的存储地址,即数组的末尾

当您执行s=s[:0]时,所做的唯一更改是将s的长度设置为0-它仍然指向相同的存储,并且仍然具有6的容量。底层数组仍然包含相同的值,除非有其他更改

当您执行s=s[:4]时,您所做的唯一更改是将s的长度设置为4-它仍然指向相同的存储,并且仍然具有6的容量。底层数组仍然具有以前的值,现在您可以通过切片再次看到它们

执行s=s[2:]时,其指针向前移动两个元素,其长度和容量减少2。底层数组仍然是相同的,但是不能使用s访问它的前两个元素,也不能从s派生新的切片,除非使用切片头执行某些操作。一旦你前进,你就不能后退


如果你想,你可以,作为你的第一步,做s=s[:0:0],这将把s的长度和容量都减少到0,使它变得无用。由于切片表达式不能增加切片的容量,因此它永远不能用于访问底层数组的任何元素,从而提供从一开始就可能发生的情况。如果您想将某些数据的视图传递给一些不受信任的代码,并确保它不会访问给定窗口之外的任何内容,那么这可能有其用途。

这有点离题了,但这样做而不仅仅使用数组有什么意义呢?切片比数组灵活得多,部分原因是重新切片功能,但主要是因为它们没有与其类型关联的大小。在Go中,数组类型包括大小信息;[2] int和[3]int是不同的类型。但是[]int可以用于任意数量的元素。因此,它们的行为更接近于更高级的语言数组,比如JS中的数组,而不是C中的数组?go中的数组更像C中的数组,go中的切片更像go中的切片。我不想将它们与JavaScript等不安全语言中的数组进行太近的比较,因为在大多数语言中,数组可以随意扩展,而Go切片则不是这样,因此为什么append会返回一个新切片。
initial := []string{"foo", "bar", "baz"}
s1 := initial[:1]
initial[0] = "qux"
fmt.Println(s1)