GO切片问题:一个切片从中间删除用另外一个变量接收原切片值变化的原理是啥?

一个go切片的问题

    var i = 3
    nums := []int{1, 2, 3, 4, 5, 6}
    nums6 := append(nums[:i], nums[i+2:]...)
    fmt.Println(nums, nums6)

这段代码nums 最终输出为什么变成了[1,2,3,6,5,6]
输出内容为:// [1 2 3 6 5 6] [1 2 3 6]
看这个输入nums应该是改动了,但是为什么5,6又还在呢

阅读 921
avatarAI BotBETA

在 Go 语言中,切片是对底层数组的引用,而不是对底层数组的一个副本。这意味着当你创建一个新的切片时,如果你没有创建新的底层数组,那么新的切片和原来的切片会共享同一个底层数组。

现在,让我们分析你提供的代码:

var i = 3
nums := []int{1, 2, 3, 4, 5, 6}
nums6 := append(nums[:i], nums[i+2:]...)
fmt.Println(nums, nums6)
  1. nums 是一个包含 6 个整数的切片。
  2. i 被设置为 3。
  3. nums6 是通过 append 函数创建的,该函数将 nums 切片的前 i 个元素(即 nums[:i])和从 i+2 开始到 nums 结尾的所有元素(即 nums[i+2:])合并到一个新的切片中。

这里的关键是 append 函数如何工作。在 Go 中,append 函数可能会重新分配底层数组,特别是当切片没有足够的容量来容纳额外的元素时。但是,在你的例子中,nums[:i]nums[i+2:] 都没有超出 nums 的容量,所以 append 函数不需要重新分配底层数组。

因此,nums6 切片和 nums 切片共享同一个底层数组。当你修改 nums 切片时(在这个例子中是 nums[i] = 6),你实际上是在修改两个切片共享的底层数组。

最终,当你打印 numsnums6 时,你会看到 nums 的值已经被改变,因为它和 nums6 共享同一个底层数组。

为了避免这种情况,你可以在创建 nums6 时创建一个新的底层数组,如下所示:

nums6 := append([]int{}, nums[:i]...)
nums6 = append(nums6, nums[i+2:]...)

这样,nums6 会有一个独立的底层数组,对 nums6 的修改不会影响 nums

2 个回答

看官方对 append 描述,Appending_and_copying_slices

首先 append 用法:

append(s S, x ...E) S // core type of S is []E

里面这么说的:

If the capacity of s is not large enough to fit the additional values, append allocates a new, sufficiently large underlying array that fits both the existing slice elements and the additional values. Otherwise, append re-uses the underlying array.

如果 append 之后的数据并没有超过 s 原本的容量,那么就会利用原本的 底层数组,也就是你等于是在原切片的底层数据上对应位置进行了改动。

然后对于切片的解释: slices-intro
golang中切片由三部分组成:
image.png

所以结合 append 不超过原本切片对象的容量时候,在原本指针所指向的 underlying array 做了修改,并返回;如果超过原本切片的容量,那就会重新 reallocate 一个新的 underlying array予以返回。

将你的例子进行扩展,不改变容量的时候:

nums8 := append(nums[:4], 100)
fmt.Println("------", nums8, nums)
// ------ [1 2 3 4 100] [1 2 3 4 100 6]

就是这个道理。。。

slice 里只记录了 underlying array 跟 length 一类的 meta data。

append 不会直接改变 nums ,而是修改了 underlying array 的内容,并且重新生成了一个新的 slice (nums6) 。

所以 nums 的 length 是没有变化。

另外 array 的长度是不能修改的。所以对 nums 来说,它的 underlying array 被修改了一个元素,长度没有变化,最后的 5,6 就都还在

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题