初始化:數組需要指定大小,不指定也會根據初始化的自動推算出大小,不可改變
數組:
a := [...]int{1,2,3} a := [3]int{1,2,3}
切片:
a:= []int{1,2,3} a := make([]int, 5) a := make([]int, 5, 10)
slice的數據結構:
go源碼slice的數據結構定義:
type slice struct { array unsafe.Pointer len int cap int }
一個指向真實 array 地址的指針 ptr ,slice 的長度 len 和容量 cap
函數傳遞:數組需要明確指定大小,切片不需要。數組是值傳遞,切片是地址傳遞
numbers2 := [...]int{1, 2, 3, 4, 5, 6} maxIndex2 := len(numbers2) - 1 for i, e := range numbers2 { if i == maxIndex2 { numbers2[0] += e } else { numbers2[i+1] += e } } fmt.Println(numbers2) numbers3 := []int{1, 2, 3, 4, 5, 6} maxIndex3 := len(numbers3) - 1 for i, e := range numbers3 { if i == maxIndex3 { numbers3[0] += e } else { numbers3[i+1] += e } } fmt.Println(numbers3)
輸出:
[7 3 5 7 9 11] [22 3 6 10 15 21]
觀察slice append的時候內存地址會不會改變:
通過一個例子:
package main
import (
"fmt"
"unsafe"
)
func main() {
//說先定義一個切片,只限定長度為1
s := make([]int, 1)
//打印出slice的長度,容量以及內存地址
fmt.Printf("len :%d cap:%d array ptr :%v \n", len(s), cap(s), *(*unsafe.Pointer)(unsafe.Pointer(&s)))
for i := 0; i < 5; i++ {
s = append(s, i)
fmt.Printf("len :%d cap:%d array ptr :%v \n", len(s), cap(s), *(*unsafe.Pointer)(unsafe.Pointer(&s)))
}
//打印出slice
fmt.Println("array:", s)
}
輸出:
len :1 cap:1 array ptr :0xc042062080 len :2 cap:2 array ptr :0xc0420620c0 len :3 cap:4 array ptr :0xc0420600e0 len :4 cap:4 array ptr :0xc0420600e0 len :5 cap:8 array ptr :0xc0420880c0 len :6 cap:8 array ptr :0xc0420880c0 array: [0 0 1 2 3 4]
可以看出來在append的過程中,內存地址有些是一樣的,有些是不一樣的,容量也是如此
看出來了吧,每次cap改變的時候指向array內存的指針都在變化。當在使用 append 的時候,如果 cap==len 了這個時候就會新開辟一塊更大內存,然后把之前的數據復制過去。
- 而cap是以乘以2的速度擴展的。這里是不是真的就是乘以2的速度呢??
- 最后一句輸出slice元素的時候為什么會多了一個0呢??
對於問題2:是因為make初始化時,都會初始化成對應數據類型的原值
我們再來測試一下問題1:
package main import ( "fmt" "unsafe" ) func main() { //說先定義一個切片,只限定長度為1 s := make([]int, 1) //打印出slice的長度,容量以及內存地址 fmt.Printf("len :%d cap:%d array ptr :%v \n", len(s), cap(s), *(*unsafe.Pointer)(unsafe.Pointer(&s))) for i := 1; i < 1024*2; i++ { s = append(s, i) fmt.Printf("len :%d cap:%d array ptr :%v \n", len(s), cap(s), *(*unsafe.Pointer)(unsafe.Pointer(&s))) } //打印出slice fmt.Println("array:", s) }
輸出太多了,就截一部分:
如果按照上面得出的結論,那cap為1024的下一個應該是2048,但是卻是1280
實際go在append的時候放大cap是有規律的。在 cap 小於1024的情況下是每次擴大到 2 * cap ,當大於1024之后就每次擴大到 1.25 * cap 。