日常開發中slice經常用,就是對於一個老司機來說有時也容易忽略。一起看下:
//Slice 數據結構
type Slice struct {
ptr unsafe.Pointer // Array pointer
len int // slice length
cap int // slice capacity
}
//使用make創建
make([]T, length, capacity)
len()取數組長度,在內存中進行了初始化實際存在的元素的個數
cap()取數組容量,最大可存放元素個數(每次cap改變的時候指向array內存的指針都在變化)
注意:slice的容量,如果通過make函數創建slice的時候指定了容量參數,那內存管理器會根據指定的容量的值先劃分一塊兒內存空間,然後才在其中按長度,存放數組元素,多餘的部分處於空閒狀態。
在slice上追加元素的時候,首先會到這塊兒空閒的內存中,如果添加的元素的個數超過了容量的值,內存管理器會重新劃分一塊容量值為原容量2倍大小的內存空間,這個機制可以提升運算性能,因為內存的頻繁重新劃分會降低性能。
實際go在append的時候放大cap是有規律的。在 cap 小於1024的情況下是每次擴大到 2 * cap ,當大於1024之後就每次擴大到 1.25 * cap 。
在實際使用中,我們最好事先預期好一個cap,這樣在使用append的時候可以避免反覆重新分配內存複製之前的數據,減少不必要的性能消耗。
示例:
package main
import "fmt"
func main() {
/* 創建切片 */
numbers := []int{0,1,2,3,4,5,6,7,8}
printSlice(numbers)
/* 打印原始切片 */
fmt.Println("numbers ==", numbers)
/* 打印子切片從索引1(包含) 到索引4(不包含)*/
fmt.Println("numbers[1:4] ==", numbers[1:4])
/* 默認下限為 0*/
fmt.Println("numbers[:3] ==", numbers[:3])
/* 默認上限為 len(s)*/
fmt.Println("numbers[4:] ==", numbers[4:])
numbers1 := make([]int,0,5)
printSlice(numbers1)
/* 打印子切片從索引 0(包含) 到索引 2(不包含) */
number2 := numbers[:2]
printSlice(number2)
/* 打印子切片從索引 2(包含) 到索引 5(不包含) */
number3 := numbers[4:5]
printSlice(number3)
number3 = append(number3, 4,5,6,7,8)
printSlice(number3)
}
func printSlice(x []int){
fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}
執行以上代碼輸出結果為:
len=9 cap=9 slice=[0 1 2 3 4 5 6 7 8]
numbers == [0 1 2 3 4 5 6 7 8]
numbers[1:4] == [1 2 3]
numbers[:3] == [0 1 2]
numbers[4:] == [4 5 6 7 8]
len=0 cap=5 slice=[]
len=2 cap=9 slice=[0 1]
len=3 cap=5 slice=[4] //此時指針已經到index 2 處,所以cap容量為9-2=7
len=6 cap=10 slice=[5 6 4 5 6 7 8] //此時cap已經擴容為2倍
更多內容請關注每日編程,每天進步一點。
閱讀更多 每日編程 的文章