赞
踩
先看测试例子1:
func testModifyElem(s []int) { s[0] = 1 fmt.Printf("s inter address is %p \n", s) fmt.Println("s=", s) } func main() { fmt.Println("------------------------ slice0 -------------------------") sa := make([]int, 10) fmt.Printf("sa address is %p \n", sa) fmt.Println("sa=", sa) testModifyElem(sa) fmt.Printf("post sa address is %p \n", sa) fmt.Println("post sa=", sa) }
输出结果是:
------------------------ slice0 -------------------------
sa address is 0xc00001e0a0
sa= [0 0 0 0 0 0 0 0 0 0]
s inter address is 0xc00001e0a0
s= [1 0 0 0 0 0 0 0 0 0]
post sa address is 0xc00001e0a0
post sa= [1 0 0 0 0 0 0 0 0 0]
上面的testModifyElem函数传递的是 slice 对象,输出结果可以看出两点:
这种现象会给人一种感觉,golang slice的传递是引用传递(实际上是错误的)。我们再来看一个例子:
func testModifyElem2(s []int) { s[0] = 1 fmt.Printf("s inter address is %p \n", s) fmt.Println("s=", s) s = append(s, 11) fmt.Printf("s inter address(after append) is %p \n", s) fmt.Println("s=(after append)", s) } func main() { fmt.Println("------------------------ slice0 -------------------------") sa := make([]int, 10) fmt.Printf("sa address is %p \n", sa) fmt.Println("sa=", sa) testModifyElem2(sa) fmt.Printf("post sa address is %p \n", sa) fmt.Println("post sa=", sa) }
输出结果是:
------------------------ slice0 -------------------------
sa address is 0xc00009e000
sa= [0 0 0 0 0 0 0 0 0 0]
s inter address is 0xc00009e000
s= [1 0 0 0 0 0 0 0 0 0]
s inter address(after append) is 0xc0000b0000
s=(after append) [1 0 0 0 0 0 0 0 0 0 11]
post sa address is 0xc00009e000
post sa= [1 0 0 0 0 0 0 0 0 0]
从这个输出结果我们可以得到:
还有一种场景,如果slice在函数内部append不会导致扩容呢?看下面的例子:
func testModifyElem2(s []int) { s[0] = 1 fmt.Printf("s inter address is %p \n", s) fmt.Println("s=", s) s = append(s, 11) fmt.Printf("s inter address(after append) is %p \n", s) fmt.Println("s=(after append)", s) } func main() { fmt.Println("------------------------ slice0 -------------------------") sa := make([]int, 10, 20) fmt.Printf("sa address is %p \n", sa) fmt.Println("sa=", sa) testModifyElem2(sa) fmt.Printf("post sa address is %p \n", sa) fmt.Println("post sa=", sa) }
运行结果如下:
------------------------ slice0 -------------------------
sa address is 0xc0000ac000
sa= [0 0 0 0 0 0 0 0 0 0]
s inter address is 0xc0000ac000
s= [1 0 0 0 0 0 0 0 0 0]
s inter address(after append) is 0xc0000ac000
s=(after append) [1 0 0 0 0 0 0 0 0 0 11]
post sa address is 0xc0000ac000
post sa= [1 0 0 0 0 0 0 0 0 0]
我们可以看到两点:
这个结论进一步验证了我们的结论。
所以我们的结论就是:值传递。
当我们调用函数 testMethod(s) 的时候,实际上类似于 testMethod(*addr, len, cap)。
其实我们在调用append函数的时候,用法都是 s = append(s, data...)
。 append函数实际上返回的是一个新的slice对象,然后新的对象的属性;len、cap以及底层数组首地址会拷贝赋值给s。
前面一章其实已经列出了slice传参的一些坑。这里再列出一些典型的坑。
Case1: 函数入参是一个slice, 期待函数内部的的修改,比如新增、删除、更改会在外部生效。
这里的实现有两种方法:传一个slice的指针进去;或者return入参的slice并且赋值给外部的slice。
(1)传指针, 直接看code:
func testSlicePtr(sp *[]int) {
fmt.Printf("sp address is %p \n", *sp)
fmt.Println("sp=", *sp
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。