Golang Go语言新手求助,关于 slice 的问题。

Golang Go语言新手求助,关于 slice 的问题。

func main() {
s2 := make([]int, 0, 10)
fmt.Printf("%p\n", s2)
addValue(s2)
fmt.Println(s2)
}

func addValue(list []int) { fmt.Printf("%p\n", list) list = append(list, 1, 2, 3, 4) fmt.Println(list) fmt.Printf("%p\n", list) }

最后打印出的结果是:

0x140000b4000
0x140000b4000
[1 2 3 4]
0x140000b4000
[]

为什么 s2 和 list 指向的地址相同,保存的值不同呢


更多关于Golang Go语言新手求助,关于 slice 的问题。的实战教程也可以访问 https://www.itying.com/category-94-b0.html

16 回复

func addValue(list []int) []int{
fmt.Printf("%p\n", list)
list = append(list, 1, 2, 3, 4)
fmt.Println(list)
fmt.Printf("%p\n", list)
return list
}

更多关于Golang Go语言新手求助,关于 slice 的问题。的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


因为 slice 除了起始地址之外还保存了长度,你 main 函数里面的 s2 长度还是 0 ,长度还是 0 的原因的参数是值传递,addValue 里面修改的是拷贝一次的 slice 结构,而不是 main 函数里的 s2

函数都是值拷贝,sli 是引用类型,list 拷贝了 sli 的地址,直接输出地址肯定一样了。

可以这样理解,一个 slice 实际是一个 []int + 长度。
你在函数里 addValue 之后,数组的下一位其实是赋值成功的。(如果没有触发 Slice 重新分配数组内存)
但是,长度是 “形参” ,函数内的改变不会影响函数外部。

也就是说,其实整个过程,是赋值成功的,但是,由于长度没有发生变化,addValue 外部的逻辑无法感知到新添加的元素。

想要验证的话,可以通过 unsafe 获取 addValue 添加元素的地方的那块内存,会发现实际是添加成功了的。

顺便一提,如果 addValue 的过程中,数组的长度达到阈值了,那么就会触发 Slice 重新分配内存,这个时候,传入函数中的 那个时刻的那个 数组 ,实际上是没有任何变化的。




谢谢各位,明白了

非常感谢,明白了

package main

import (
“fmt”
“testing”
)

func Test_test33(T *testing.T) {
test33()
}

func test33() {
s2 := make([]int, 2, 10) //初始长度 2
s2 = append(s2, 66, 88) //长度+2
fmt.Println(s2) //s2 总长度 =4
fmt.Printf("%p\n", s2)
addValue(s2) //传递 切片底向的 底层数组 针针
fmt.Println(s2) //s2 总长度 4 并没有改变

s2 = s2[:8] //如果改变切片 s2 的长度 =list 长度,
fmt.Println(s2) // 是不是和 list 输出一样了
}

func addValue(list []int) {
fmt.Printf("%p\n", list) //此切片 list 并不完全等于 切片 s2,切片之间也是无法进行比较的,list 只是和 s2 共用同一底层数组 ,切片 还有长度和容量
list = append(list, 1, 2, 3, 4) //list 长度 +4 ,此操作 并不会改变 s2 的切片长度
fmt.Printf("%p\n", list)
fmt.Println(list)

}

自己写过一篇关于 slice 参数传递的文章,可以看看

https://blog.ljyngup.com/archives/868.html/

go slice 的 api 太不直观了。好像是肯汤普森写的。

#9 博客不错

你的 len 是 0 ,然后你追加的话原来的放不下,就会重新分配一个,你打印一下追加后的 list 就会发现和前面不一样了

你好,作为Go语言方面的专家,很高兴能帮助你解决关于slice的问题。

在Go语言中,slice是一种非常强大且灵活的数据结构,它基于数组构建,但提供了动态长度的特性。对于新手来说,slice的一些行为可能会让人感到困惑。

首先,slice是一个包含三个字段的数据结构:指向数组的指针(Pointer)、切片的长度(Length)以及切片的容量(Capacity)。当你对一个slice进行切片操作时,例如s2 := s1[1:3],你实际上是在创建一个新的slice,它共享了原始slice所指向的数组的一部分。

这里有几个常见的slice操作需要注意:

  1. append操作:向slice追加元素时,如果slice的容量不足,Go会分配一个新的底层数组,并复制原有元素到新的数组中。

  2. 切片操作:切片操作不会改变原始slice的内容,而是返回一个新的slice,它可能共享原始slice的底层数组。

  3. 容量问题:由于slice可能共享底层数组,因此修改一个slice的元素可能会影响到另一个slice(如果它们共享相同的底层数组部分)。

如果你遇到了具体的slice问题,比如内存泄漏、性能瓶颈或者代码实现上的困惑,可以详细描述一下你的问题场景,这样我可以给出更具体的建议和解决方案。希望这些信息对你有所帮助!

回到顶部