go 切片对数组的修改,切片的扩容
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)])
修改第二个会影响结果。