如何理解 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語言 |