package main
import (
"fmt"
)
func test(a []int) {
a = append(a, 4)
}
func main() {
s := make([]int, 3, 4)
s[0] = 1
s[1] = 2
s[2] = 3
fmt.Println(s)//1, 2, 3
test(s)
fmt.Println(s)//1, 2, 3
}
我认为第二个 println 打印出来的应该是 1, 2, 3, 4, 但是实际打印的是 1, 2, 3
1
zoowii 2020-03-04 11:48:34 +08:00
a=append(a, 4)执行前后的 a 不是同一个 slice, 参数 a 传的是引用的值,不改变原来的 s 变量
|
2
yujianwjj OP @zoowii cap(a) 是 4,实际 len(a) 是 3,为啥 append 前后的 a 不是同一个 slice ?
|
3
kuro1 2020-03-04 11:51:31 +08:00
老一套 指针问题
|
5
lhx2008 2020-03-04 11:56:33 +08:00
s 这个 struct 没有被改,里面存了 len 的数据,a 是另外一个 struct
|
6
AzadCypress 2020-03-04 12:02:46 +08:00 via Android 1
type slice struct{
array unsafe.Pointer len int cap int } 当你用 slice 作为参数时,传进去的是这个结构体的 copy 所以改变 slice 中的值是有效的,涉及到长度 /容量的在副本上进行 是无效的 |
8
cmdOptionKana 2020-03-04 12:06:18 +08:00
你把 test 函数改成这样
func test(a *[]int) { *a = append(*a, 4) } 然后这样调用 test(&s) 就可以了。 |
9
ifconfig 2020-03-04 14:11:19 +08:00
这是值传递,很多语言都是值传递吧
|
10
zhs227 2020-03-04 14:22:04 +08:00 3
说到点子上的人不多。除了 auta,外面的 s.len 没变,但是 s[4]的内容实际是有了,只是 length 仍然是 3.
具体可以看看 playground: https://play.golang.org/p/JjP8z4xQ1Qa |
11
luoqeng 2020-03-04 14:39:11 +08:00
底层用的同一块内存,但是 s 与 a 的里记录的长度不一样。
|
12
luoqeng 2020-03-04 15:08:03 +08:00
sSliceArrayPointer := unsafe.Pointer(*(*unsafe.Pointer)(unsafe.Pointer(&s)))
offset3Pointer := unsafe.Pointer(uintptr(sSliceArrayPointer ) + unsafe.Sizeof(&s[0])*3) fmt.Println("offset s[3]:", *(*int)(offset3Pointer)) 输出 offset s[3]: 4 |
13
CEBBCAT 2020-03-04 18:38:34 +08:00
|
14
visitant 2020-03-04 18:50:35 +08:00
slice 实际上是一个结构体 struct{ptr,len,cap},ptr 指向存储数据的数组,len/cap 表示当前长度和容量,你传到函数内的是一个 struct 的拷贝,在一个内部函数 append 不会影响到外部函数的 len.
|
15
index90 2020-03-04 18:53:16 +08:00
你把 slice 类型看作是一个大概这样子的 struct
type Slice struct { len int mem *unsafe.Pointer ... other info } 函数参数是值传递,就是把 s 复制了一遍到 a 其实 a 和 s 只是用了同一个内存指针,其他都是独立的 |
16
v2exe2v 2020-03-04 18:54:51 +08:00
func test(a []int) 这里的 a 是 s 的一个拷贝,所以对 a 的修改不影响外面的 s。我猜传 *[]int 可以
|
18
kuro1 2020-03-05 10:59:12 +08:00
```
package main import ( "fmt" ) func test(a []int) []int{ a = append(a, 4) return a } func main() { s := make([]int, 3, 4) s[0] = 1 s[1] = 2 s[2] = 3 fmt.Println(s) //[1 2 3] a := test(s) fmt.Println(a) //[1 2 3 4] s = append(s,5) fmt.Println(s) //[1 2 3 4] fmt.Println(a) //[1 2 3 5] } ``` |
19
kuro1 2020-03-05 11:03:04 +08:00
更正,最后两行
fmt.Println(s) //[1 2 3 5] fmt.Println(a) //[1 2 3 5] |
20
newmiao 2020-03-07 17:30:51 +08:00
建议了解下 slice 底层结构,再加上 Go 里传参都是值传递就好理解了
https://www.v2ex.com/t/650724 |
21
ericuni 2020-03-09 13:11:59 +08:00
test 把新的 slice 返回回来, 然后 caller 再捕获才行, 本质还是值拷贝, slice 只是一个 slice header
|