1. 程式人生 > >golang slice切片的原理以及內置函數cap, len

golang slice切片的原理以及內置函數cap, len

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