func main() {
nums := make([]int, 0, 10)
// go 语言都是值传递
// 例如,当我们传递一个slice时, 实际上在调用函数的函数栈帧中,会复制一个sliceHeader结构体, // Data 指向原slice的底层数组,go语言中如果我们传入的是内存中的一块地址,则我们可以修改这块内存上// 的值
var appendNum = func(a []int) {
a = append(a, 1, 2, 3)
fmt.Println(a, len(a), cap(a))
//fmt.Print input slice will point the data prt of sliceHeader
fmt.Printf("a addr %p\n", a)
}
appendNum(nums)
fmt.Println(nums)
fmt.Printf("num addr %p\n", nums)
fmt.Println(nums[:3], len(nums), cap(nums))
}
// 输出的是
// [1 2 3] 3 10
// a addr 0xc0000b20f0
// []
// num addr 0xc0000b20f0
// [1 2 3] 0 10
// 所以当我们在call appendNum之后,参数slice a的底层数组指向nums的底层数组(地址相同),当append数据之后,data指向的内存被修改,但是nums的len和cap还是原来的值,因此最后输出的是[1 2 3] 0 10
func main() {
nums := make([]int, 0, 2)
var appendNum = func(a []int) {
a = append(a, 1, 2, 3)
fmt.Println(a, len(a), cap(a))
//fmt.Print input slice will point the data prt of sliceHeader
fmt.Printf("a addr %p\n", a)
}
appendNum(nums)
fmt.Println(nums)
fmt.Printf("num addr %p\n", nums)
fmt.Println(nums[:2], len(nums), cap(nums))
}
输出
[1 2 3] 3 4
a addr 0xc0000181a0
[]
num addr 0xc00000a0d0
[0 0] 0 2
对比上一段代码,这一段代码我们将nums的cap设置为2,但是我们append3个数据在a中,这会触发append的扩容机制,预估容量newsize为3, oldsize*2 = 4;newsize < oldsize *2 且old<1024 所以a会重新开辟一个新的底层数据,newsize = 2*oldsize。
上边讲述了为什么在appendNum中的cap(a) = 4, 可以发现最后输出的nums[:2] 为[0, 0], 所以a操作的底层数组已经变成另一个了。
// 注 : nums与nums[:] 等价于nums[0:len(nums)],而nums[low:high],high最大可以等于cap(nums)