golang slice切片的原理以及內置函數cap, len
阿新 • • 發佈:2019-03-10
print make panic 一個數 常用 true 數組 tle pac
golang中map, slice(切片)是常用的類型, slice是對數組進行封裝, 可以避免一些坑
package main
import (
"fmt"
"strconv"
)
func testLenCap() {
strs := make([]string, 5, 10) //可以只有一個數字參數, 那麽cap=len, make([]string, 5, 5) 等價於 make([]string, 5)
fmt.Printf("value=%v, is nil=%v\n", strs, strs == nil)
//strs := []string{"0", "1", "2", "3", "4"} //當然這種方式是直接賦值了, 忽略賦值等價於 make([]string, 5)
for i := 0; i < len(strs); i++ {
strs[i] = strconv.Itoa(i)
}
fmt.Printf("len=%v, cap=%v, strsAddress=%p, valueAddress=%p\n", len(strs), cap(strs), &strs, strs) //%p內存地址
for i := len(strs); i < cap(strs); i++ {
//strs[i] = strconv.Itoa(i) //panic
strs = append(strs, strconv.Itoa(i)) //使用append向數組追加數據}
fmt.Printf("len=%v, cap=%v, strsAddress=%p, valueAddress=%p\n", len(strs), cap(strs), &strs, strs) //內存地址不變
strs = append(strs, "10")
fmt.Printf("len=%v, cap=%v, strsAddress=%p, valueAddress=%p\n", len(strs), cap(strs), &strs, strs) //內存地址改變
//strs2自身的地址與strs不一樣, 但實際數組的內存地址不變, 改變strs, strs2其中任意一個變量, 另一個隨之改變strs2 := strs[:]
fmt.Printf("len=%v, cap=%v, strsAddress=%p, valueAddress=%p\n", len(strs2), cap(strs2), &strs2, strs2)
strs2[5] = "1000"
fmt.Printf("strs[5]=%s\n", strs[5])
//strs3自身的地址與strs不一樣, 實際數組的內存地址也不一樣, 互不幹擾.
startIndex := 5
strs3 := strs[startIndex:7]
fmt.Printf("len=%v, cap=%v, strsAddress=%p, valueAddress=%p\n", len(strs3), cap(strs3), &strs3, strs3)
fmt.Printf("cap(strs3) == cap(strs)-startIndex : %v", cap(strs3) == cap(strs)-startIndex)
}
func main() {
testLenCap()
}
控制臺打印結果:
value=[ ], is nil=false
len=5, cap=10, strsAddress=0xc0420023e0, valueAddress=0xc04203e0a0
len=10, cap=10, strsAddress=0xc0420023e0, valueAddress=0xc04203e0a0
len=11, cap=20, strsAddress=0xc0420023e0, valueAddress=0xc042040140
len=11, cap=20, strsAddress=0xc0420024a0, valueAddress=0xc042040140
strs[5]=1000
len=2, cap=15, strsAddress=0xc0420024e0, valueAddress=0xc042040190
cap(strs3) == cap(strs)-startIndex : true
可以看到:
len函數是實際數據存長度;
cap是最大容量,可以避免反復分配內存;
擴容機制是翻倍, 所以go的擴容很快, 尤其是基數很大的情況下. 但如果能預先分配cap, 即使再快也是無畏的消耗
使用原切片創建新切片時, 應註意每個切片的值, 避免出現與預想不一樣的情況
golang slice切片的原理以及內置函數cap, len