书上给了一道题
package main
import (
"fmt"
)
func AddElement(slice []int, e int) []int {
return append(slice, e)
}
func main() {
var slice []int
slice = append(slice, 1, 2, 3)
newSlice := AddElement(slice, 4)
fmt.Println(&slice[0] == &newSlice[0])
}
书中给出的参考答案:
append函数执行时会判断切片容量是否能够存放新增元素,如果不能,则会重新申请存储空间,新存储空间将是原来的2倍或1.25倍(取决于扩展原空间大小),本例中实际执行了两次append操作,第一次空间增长到4,所以第二次append不会再扩容,所以新旧两个切片将共用一块存储空间。程序会输出”true”。
不知道作者所用的golang+平台是哪个,我用的是go version go1.16.4 linux/arm64
得出的结果跟作者不同。
slice = append(slice,1,2,3) 这行代码,空间是3 并不是4.。如果是4 就跟书中作者分析的一样,按照实际运行的是3。所以再次append的时候 就扩容了。
一:基本结构
type slice struct {
array unsafe.Pointer
len int
cap int
}
从基本结构上可以看出,slice在发生值传递的时候,len和cap是复制了一份的,也就是说可视范围都是独立的。
二:注意事项
a[low : high : max] // 0 <= low <= high <= max <= cap(a)
cap = max - low,low和high 是左闭右开
1.1:创建方式
make: slice := make([]int, 5, 10)
array: slice := array[5:7]
1.2:copy不会发生扩容
使用copy()内置函数拷贝两个切片时,会将源切片的数据逐个拷贝到目的切片指向的数组中,拷贝数量取两个切片长度的最小值。例如长度为10的切片拷贝到长度为5的切片时,将会拷贝5个元素。也就是说,copy过程中不会发生扩容。
三:扩容策略
参看前边的文章:Golang slice扩容深度分析_zhangdell的专栏-CSDN博客
四:坑
切片之间是不能比较的,不能用==去比较2个切片。切片唯一合法的比较操作是和nil去比较。
一个值为nil的切片是没有底层数组的,它的长度和容量是0。但是我们不能说一个长度和容量是0的切片 一定是nil。比如
var s1 []int //len(s1)=0;cap(s1)=0;s1==nil
s2 := []int{} //len(s2)=0;cap(s2)=0;s2!=nil
s3 := make([]int, 0) //len(s3)=0;cap(s3)=0;s3!=nil
所以判断一个切片是不是空,要用len(s) == 0 不能用s == nil。