go中數組是值拷貝,
切片是對上層數組的表示,應該是使用的是數組地址,修改時是直接對原來的數組進行修改
切片作為函數參數依舊如此
slice或者array作為函數參數傳遞的時候,本質是傳值而不是傳引用。傳值的過程復制一個新的切片,這個切片也指向原始變量的底層數組。
var array [5]int=[5]int{1,2,3,4,5}//可以簡化為array:=[5]int{1,2,3,4,5} 初學所以沒有簡化
var slice[]int =array[1:3]
fmt.Println(array)
for i:=range slice{
slice[i]+=100
}
fmt.Println(array)
fmt.Println(slice)
輸出
說明切片是對數組的引用,更改切片時原數組會發生變化。
因為切片保留對數組的引用,切片在,數組內存不能回收,所以數組大而使用切片為其中一小部分時應該使用切片的拷貝方式。
var array [7]int=[7]int{1,2,3,4,5,6,7}
var slice[]int =array[:3]
sliceneed:=make([]int,len(slice))
copy(sliceneed,slice)
fmt.Println(sliceneed)
結果
追加一個一個切片到另一個后面可以用append方式帶...
var array [5]int=[5]int{1,2,3,4,5}//可以簡化為array:=[5]int{1,2,3,4,5} 初學所以沒有簡化
var slice[]int =array[1:3]
fruits := []int{6,7}
slice =append(slice,fruits...)
9.24增加切片擴容機制
部分源碼
// src/runtime/slice.go
func growslice(et *_type, old slice, cap int) slice {
// ...省略部分
newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {//大於兩倍使用多的容量
newcap = cap
} else {
if old.len < 1024 {//小於1024 使用兩倍
newcap = doublecap
} else {//否則依次擴大25%,直到復合容量
// Check 0 < newcap to detect overflow
// and prevent an infinite loop.
for 0 < newcap && newcap < cap {
newcap += newcap / 4
}
// Set newcap to the requested cap when
// the newcap calculation overflowed.
if newcap <= 0 {
newcap = cap
}
}
}
// ...省略部分
}
- 當需要的容量超過原切片容量的兩倍時,會使用需要的容量作為新容量。
- 當原切片長度小於1024時,新切片的容量會直接翻倍。而當原切片的容量大於等於1024時,會反復地增加25%,直到新容量超過所需要的容量。
copy
來復制數據,保證得到一個新的切片,
避免后續操作帶來預料之外的副作用。
參考鏈接:https://www.jianshu.com/p/54be5b08a21c
預測輸出
var x =[]int{1,2,3}
var y = x[:2]
y = append(y,50)
y = append(y,60)
fmt.Println(x)
y[0] = 20
fmt.Println(y)
結果,y初始和x引用相同底層數組,切容量未超出,所以第一個append正常修改,
第二個append時超出容量,擴容使用新的底層數組,之后再修改y是更改自己的數據。
今天寫leetcode遇到個奇怪的問題。
一個切片append另外一個,是非拷貝方式的,修改第二個切片值會影響結果
test:=[]int{1,2,3} two:=[]int{4,5,6} two[0] = 9 test = append(test,two...) fmt.Println(test[:len(test)])
修改第二個會影響結果。