
開始之前,先看下下面這個(gè)例子,
package main
import "fmt"
func main() {
s := make([]int, 0, 10)
s1 := append(s, 1)
s1 = append(s1, 3)
s2 := append(s, 2)
s2 = append(s2, 4)
fmt.Printf("%v\\n", s1)
fmt.Printf("%v\\n", s2)
}
這個(gè)輸出什么 , [1,3] [2,4]?
錯(cuò)?,輸出的是[2,4] , [2, 4]。
為什么
- 先來看下slice,
type slice struct {
array unsafe.Pointer
len int
cap int
}
可以看出 Slice 數(shù)據(jù)結(jié)構(gòu)是 指針 ,容量(可以存儲(chǔ)數(shù)據(jù)的大?。L(zhǎng)度(當(dāng)前數(shù)據(jù)的大?。?。使用上 ,make可以為其分配空間。
make([]int, 0, 10)
- 這里有個(gè)注意點(diǎn),append操作,append(slice, …),
- 如果slice開辟的空間足夠,則不用額外分配空間。 append的返回結(jié)果的空間仍然是slice原有分配的空間,只是基于這個(gè)空間賦值,然后返回
- 如果slice開辟的空間不足,則重新開辟空間,賦值,然后返回。
- 再帶入這個(gè)例子,
s := make([]int, 0, 10)
s1 := append(s, 1)
s1 = append(s1, 3)
s2 := append(s, 2)
s2 = append(s2, 4)

站在第二個(gè)slice的角度s2上看,先拿到一塊內(nèi)存空間,然后從這個(gè)空間的第一個(gè),第二個(gè)位置分別寫入值。則此時(shí)會(huì)把s1之前寫入的覆蓋掉。
結(jié)語
- append追加元素,如果slice還有容量的話,則會(huì)繼續(xù)使用原先開票的空間。不會(huì)重新開辟空間。
- 當(dāng)?shù)讓訑?shù)組裝不下的時(shí)候,Go就會(huì)創(chuàng)建新的底層數(shù)組來保存這個(gè)切片,slice地址也隨之改變。
append是否返回新地址,和原有容量和添加數(shù)據(jù)數(shù)量有關(guān),不是固定的。所以一定不要默認(rèn)append會(huì)進(jìn)行新的內(nèi)存開辟,更不要拿append 作為復(fù)制操作,認(rèn)為append完以后拿到的slice一定就是全新獨(dú)立的slice。
所以在使用append的時(shí)候,一定小心謹(jǐn)慎,認(rèn)真看好空間的分配,防止相同地址被覆蓋寫入。