我有一个数组和一个指向它的切片,如下所示:
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
问题:
在第3步:为什么切片的cap
从4跳到8?
在切片生长后的步骤4:中,对切片元素的更改(在数组范围内)不会反映到数组中,反之亦然。为什么它长大后不会发生?切片长出后会发生什么?
答案 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)
这与切片的工作原理相同(我只是无法找到证明它的源代码......)。所以,是的,你可能会失去一些空间,但这样可以提高效率!
你的第二个问题对我来说有点棘手,所以我希望@ Volker的答案对你来说足够清楚了!