Golang Go语言中 slice 的一个疑问
Golang Go语言中 slice 的一个疑问
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
更多关于Golang Go语言中 slice 的一个疑问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
a=append(a, 4)执行前后的 a 不是同一个 slice, 参数 a 传的是引用的值,不改变原来的 s 变量
更多关于Golang Go语言中 slice 的一个疑问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
cap(a) 是 4,实际 len(a) 是 3,为啥 append 前后的 a 不是同一个 slice ?
#2 外面的 s 的 len 没有变成 4
s 这个 struct 没有被改,里面存了 len 的数据,a 是另外一个 struct
type slice struct{
array unsafe.Pointer
len int
cap int
}
当你用 slice 作为参数时,传进去的是这个结构体的 copy
所以改变 slice 中的值是有效的,涉及到长度 /容量的在副本上进行 是无效的
懂了
你把 test 函数改成这样
func test(a *[]int) { *a = append(*a, 4) }
然后这样调用 test(&s)
就可以了。
这是值传递,很多语言都是值传递吧
说到点子上的人不多。除了 auta,外面的 s.len 没变,但是 s[4]的内容实际是有了,只是 length 仍然是 3.
具体可以看看 playground: https://play.golang.org/p/JjP8z4xQ1Qa
底层用的同一块内存,但是 s 与 a 的里记录的长度不一样。
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
slice 实际上是一个结构体 struct{ptr,len,cap},ptr 指向存储数据的数组,len/cap 表示当前长度和容量,你传到函数内的是一个 struct 的拷贝,在一个内部函数 append 不会影响到外部函数的 len.
你把 slice 类型看作是一个大概这样子的 struct
type Slice struct {
len int
mem *unsafe.Pointer
… other info
}
函数参数是值传递,就是把 s 复制了一遍到 a
其实 a 和 s 只是用了同一个内存指针,其他都是独立的
func test(a []int) 这里的 a 是 s 的一个拷贝,所以对 a 的修改不影响外面的 s。我猜传 *[]int 可以
影响的,你可以看我上面贴的 gist,也可以看看前几楼的解释
<br>package main<br><br>import (<br> "fmt"<br>)<br><br>func test(a []int) []int{<br> a = append(a, 4)<br> return a<br>}<br><br>func main() {<br> s := make([]int, 3, 4)<br> s[0] = 1<br> s[1] = 2<br> s[2] = 3<br> fmt.Println(s) //[1 2 3]<br> a := test(s)<br> fmt.Println(a) //[1 2 3 4]<br> s = append(s,5)<br> fmt.Println(s) //[1 2 3 4]<br> fmt.Println(a) //[1 2 3 5]<br>}<br>
更正,最后两行
fmt.Println(s) //[1 2 3 5]
fmt.Println(a) //[1 2 3 5]
建议了解下 slice 底层结构,再加上 Go 里传参都是值传递就好理解了
https://www.v2ex.com/t/650724
test 把新的 slice 返回回来, 然后 caller 再捕获才行, 本质还是值拷贝, slice 只是一个 slice header
当然,以下是对关于Go语言中slice疑问的专业回复:
您好!
关于Go语言中的slice,确实有很多值得探讨的地方。slice作为Go语言中的一种动态数组,提供了灵活且高效的内存管理方式。
首先,slice本质上是一个包含三个元素的结构体:指向底层数组的指针(Pointer)、slice的长度(Length)和slice的容量(Capacity)。这意味着slice本身并不存储数据,而是对底层数组的一个抽象和封装。
在使用slice时,常见的疑问可能包括:
-
slice的扩容:当向slice添加元素并超出其容量时,Go会自动分配一个新的底层数组,并将旧数组的元素复制到新数组中。扩容的具体策略(如扩容倍数)在Go的不同版本中可能有所不同。
-
slice的共享底层数组:由于slice只是底层数组的一个视图,因此不同的slice可能共享同一个底层数组。这在进行slice操作时需要注意,以避免意外的数据覆盖或丢失。
-
slice的切片操作:通过切片操作可以创建一个新的slice,这个新slice会共享原slice的底层数组,但具有不同的长度和容量。
理解这些概念对于编写高效且正确的Go代码至关重要。如果您有更具体的问题或场景,欢迎进一步讨论!
希望这个回复能帮助您更好地理解Go语言中的slice。