標籤:

如何理解 slice 的 capacity?

查了一些資料還是沒能理解, capacity 到底指什麼, 為什麼會存在這樣的關係: 0 &<= len(s) &<= cap(s)

go - Why slice length greater than capacity gives runtime error?

Go Slices: usage and internals


就是slice所指向的內存塊的實際容量。

你看下reflect模塊的SliceHeader類型加深印象。

實際上slice是一個三個欄位的對象,一個欄位存slice當前長度,一個欄位存slice所指向的內存塊的地址,一個欄位存這個內存塊的大小。

所以slice的len()操作是不遍歷的,效率很高。而slice的[:]操作(reslice),只是重新構造一個slice對象指向目標內存塊,效率也是很好的。

只有append操作有可能超過原目標內存塊的容量,會導致新開闢一塊內存。

slice的這個設計,即可以滿足讀操作的效率,又不會出現指針越界,重新切片效率也很好,但是有個坑,打算用切片操作目標內存的時候,必須小心別append過頭,否則就操作到新開啟的內存塊去了,也要小心別意外覆蓋了原slice的值。

寫了個實驗代碼,演示slice的原理和坑點: http://play.golang.org/p/QmPX3Wu2pd

package main

import "fmt"

func main() {
a := make([]int, 1)
b := make([]int, 1, 2)

a[0] = 321

fmt.Println("len(a)=", len(a), ", cap(a)=", cap(a))
fmt.Println("len(b)=", len(b), ", cap(b)=", cap(b))

a = append(a, 123)
b = append(b, 123)

fmt.Println("len(a)=", len(a), ", cap(a)=", cap(a))
fmt.Println("len(b)=", len(b), ", cap(b)=", cap(b))

c := a[:1]

fmt.Println("len(a)=", len(a), ", cap(a)=", cap(a), ", a[0]=", a[0])
fmt.Println("len(c)=", len(c), ", cap(c)=", cap(c), ", c[0]=", c[0])

// 把原slice值覆蓋了
c = append(c, 456)

fmt.Println("len(a)=", len(a), ", cap(a)=", cap(a), ", a[1]=", a[1])
fmt.Println("len(c)=", len(c), ", cap(c)=", cap(c), ", c[1]=", c[1])

// 分裂了
c = append(c, 789)
a = append(a, 666)

fmt.Println("len(a)=", len(a), ", cap(a)=", cap(a), ", a[2]=", a[2])
fmt.Println("len(c)=", len(c), ", cap(c)=", cap(c), ", c[2]=", c[2])

fmt.Println("Hello, playground")
}


推薦閱讀:

golang寫法疑問?
系統學習GO,推薦幾本靠譜的書?
王垠噴 Go 語言,許式偉贊 Go 語言,大家怎麼看?

TAG:Go語言 |