为什么这个切片会改变它的容量?

时间:2018-02-22 08:43:22

标签: go

我是golang的新手。 A Tour of Go有此代码段:

package main

import "fmt"

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

    // Slice the slice to give it zero length.
    s = s[:0]
    printSlice(s)

    // Extend its length.
    s = s[:4]
    printSlice(s)

    // Drop its first two values.
    s = s[2:]
    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 []
len=4 cap=6 [2 3 5 7]
len=2 cap=4 [5 7]

我的困惑是最后一行的cap=4 - 我认为应该保留6.最后一行容量从6变为4的原因是什么?另外,为什么只有最后一行改变了它的容量,但其他的不是?

3 个答案:

答案 0 :(得分:7)

请记住,slice将数据保存在数组中。通过删除前两个元素,我们将切片的开头移动到右边,现在在数组内部切片的开始和数组的末尾之间有更少的插槽。

切片末尾的元素删除对容量没有影响,因为数组内部切片的开始与支持数组末尾之间的距离不会改变。

这两个操作都没有修改后备阵列,只是修改切片数据。

请参阅https://blog.golang.org/go-slices-usage-and-internals观察到的行为在切片内部

部分中进行了解释

通过打印切片标题,您可以看到发生的变化

    MyAdapter adapter = new MyAdapter(getChildFragmentManager());
    Fragment fragment1 = EmptyFragment.newInstance("this is page 1");
    Fragment fragment2 = EmptyFragment.newInstance("this is page 2");
    presenter1.setxxx(fragment1);
    presenter2.setxxx(fragment2);
    adapter.addFragement(fragment1);
    adapter.addFragement(fragment2);
    viewPager.setAdapter(adapter);

在最后一次调用中,数据指针向前移动。

func printSlice(s []int) {
    sh := (*reflect.SliceHeader)(unsafe.Pointer(&s))
    fmt.Printf("header=%+v len=%d cap=%d %v\n", sh, len(s), cap(s), s)
}

答案 1 :(得分:1)

go blog通过解释数组由实际值组成,而切片则包含指向数组的指针,从而更明确地说明了这一点,更具体地说,该指针指向数组的元素:“容量是指基础数组中元素的数量( 从切片指针指向的元素开始 )”

答案 2 :(得分:0)

基本上,切片有3个元素:指向数据,长度和容量的指针。指向数据的指针是对底层数组的引用(固定大小,连续分配)。

可以将此切片的任何子集形成另一个切片。当从大小为N(m 0)个元素时,则在新切片中具有项0到m并且同时具有整个基础数组可用容量(因为指向数据的指针仍指向位置0)。因此,可以将其扩展到N而不会改变容量。

然而,如果一个切片m(m> 0)到k(k 指向数据的指针现在指向m 的位置,并且新的长度是从m到m k - 但现在我们只有容量m到N.我们永远无法访问新切片中的元素0到m。一旦我们理解它只是一个类似于其他语言/架构的指针操作,它就相当简单了。希望这会有所帮助。