不断增长的Slice和Underlying阵列GOLang

时间:2014-08-08 21:08:03

标签: go slice

我有一个数组和一个指向它的切片,如下所示:

package main

import "fmt"

func main() {

    array_str := []string{"0a","1b","2c","3d","4e"}
    slice_str:=array_str[1:4]
    fmt.Println("Initially :")
    fmt.Println("Printing 1 :Array :",array_str)
    fmt.Println("Printing 1 :Slice:",slice_str)

    //Step 1.Changing Slice and it get reflected in array
    fmt.Println("\nAfter Alteration:")
    slice_str[0]="alterd_1b"
    fmt.Println("Printing 2 :Array :",array_str)
    fmt.Println("Printing 2 :Slice:",slice_str)
    fmt.Println("len of  slice_str:",len(slice_str)," cap of         slice_str:",cap(slice_str),"len of  array_str:",len(array_str))

    //Step 2.appending to slice and it get reflected

    slice_str = append(slice_str,"apnded_elemnt")
    fmt.Println("\nAfter Apending:")
    fmt.Println("Printing 3 :Array :",array_str)//"4e" is replaced with "apnded_elemnt" in array !!
    fmt.Println("Printing 3 :Slice:",slice_str)
    fmt.Println("len of  slice_str:",len(slice_str)," cap of   slice_str:",cap(slice_str),"len of  array_str:",len(array_str))

    //Step 3.Again appending to slice so that lentght of slice is growing further to  underlaying array
    slice_str = append(slice_str,"outgrown_elemnt")
    fmt.Println("\nAfter OUT GROWING:")
    fmt.Println("Printing 4 :Array :",array_str)//obeviously out grown elemnt not added to array that is fine
    fmt.Println("Printing 4 :Slice:",slice_str)
    fmt.Println("len of  slice_str:",len(slice_str)," cap of slice_str:",cap(slice_str),"len of  array_str:",len(array_str))
    //How Capacity Become 8 here ???

    //Step 4 .Now Changing Slice element which is in Range of array to verify it reflect on array:
    fmt.Println("\nAfter Post out grown Alteration:")
    slice_str[0]="again_alterd_1b"
    fmt.Println("Printing 2 :Array :",array_str)//Change in slice is not reflectd in array .Why ?
    fmt.Println("Printing 2 :Slice:",slice_str)
}

游乐场:http://play.golang.org/p/3z52HXHQ7s

问题:

  1. 在第3步:为什么切片的cap从4跳到8?

  2. 在切片生长后的步骤4:中,对切片元素的更改(在数组范围内)不会反映到数组中,反之亦然。为什么它长大后不会发生?切片长出后会发生什么?

2 个答案:

答案 0 :(得分:4)

见这里:http://blog.golang.org/slices

简短答案:1)它通过加倍(而短暂)而增长。如果你追加一次,你也可以追加第二次,这可以避免分配。 2)这就是切片生长的方式。数组不能增长,因此会分配一个新的更大的数组,复制旧的数组,然后将一个切片指向更大的副本。

(golang.org网站上的文档非常有用,可读,简短和准确。我想建议先查看golang.org,然后再询问。)

答案 1 :(得分:2)

容量乘以2,因为它消耗较少。实际上,内存分配非常消耗,并且最好一次分配大量内存而不是每次都需要的内存。

让我们先比较一下使用连接的简单示例:每次,Go都会分配所需的内容。

var n = time.Now()
var s = ""
for i := 0; i < 1000000; i++ {
    s += "a"
}
fmt.Println(time.Now().Sub(n))
// 47.7s

现在,让我们这样做,但这次使用bytes.Buffer类型:

var n = time.Now()
var b = bytes.NewBufferString("")
for i := 0; i < 1000000; i++ {
    b.WriteString("a")
}
fmt.Println(time.Now().Sub(n))
// 18.5ms

不同之处在于Buffer分配内存的方式:当容量不足时,它会分配两倍的当前容量:

buf = makeSlice(2*cap(b.buf) + n)

Source

这与切片的工作原理相同(我只是无法找到证明它的源代码......)。所以,是的,你可能会失去一些空间,但这样可以提高效率!


你的第二个问题对我来说有点棘手,所以我希望@ Volker的答案对你来说足够清楚了!