Golang:slice之append时原数组发生变化的问题

使用append可以在slice之后追求元素,例如

nums:=[]int{1,2,3}
result:=append(nums,4)
fmt.Println(result)

这段代码很简单,输出result的值为:[1 2 3 4]
问题在于,进行这种操作时,原来的slice(即nums)所基于的数组的值会不会发生变化呢?在Golang中,如果有多个slice基于了同一个数组,则这些slice的数据是共享的(而不是每个slice复制一份)。也就说,如果改变了数组的内容,则基于它的所有slice的值都会变化这段代码中nums的值没有变化,但是并非所有时候都是如此。

回答这个问题,首先需要了解append函数实现原理:
1. 如果nums的cap够用,则会直接在nums指向的数组后面追加元素,返回的slice和原来的slice是同一个对象。显然,这种情况下原来的slice的值会发生变化!
2. 如果nums的cap不够用(上述代码就是这种情况),则会重新分配一个数组空间用来存储数据,并且返回指向新数组的slice。这时候原来的slice指向的数组并没有发生任何变化!
3. 当然,在任何情况下,返回的结果都是追加之后的slice,这一点没有问题!

以下代码用来验证这个问题:
(1)在函数test1nums的值发生变化了,因为nums[:2]的len为2,cap为3,所以追加一个元素时cap依然够用;
(2)在函数test2nums的值没有发生变化,因为nums[:2]的cap不够用,因此会重新分配一个数组用来存储新的数据,而nums存储的仍然是老数组。

func test1() {
    nums := []int{1, 2, 3}
    _ = append(nums[:2], 4)
    fmt.Println("test1:", nums)

    //nums changes because the cap is big enought, the original array is modified.

}

func test2() {
    nums := []int{1, 2, 3}
    c := append(nums[:2], []int{4, 5, 6}...)
    fmt.Println("test2:", nums)
    fmt.Println("cc:", c)

    //nums dont't change because the cap isn't big enought.
    //a new array is allocated while the nums still points to the old array.
    //Of course, the return value of append points to the new array.
}

4.为了避开这个’坑’,推荐在截取slice时使用三参数的方式,示例代码:

func main() {
    nums:=[]int{1,2,3,4,5}
    fmt.Println("111---len:",len(nums),"cap:",cap(nums))

    a:=nums[:3]
    fmt.Println("222---",len(a),cap(a))
    //output: 222--- 3 5

    b:=nums[:3:3]
    fmt.Println("333---",len(b),cap(b))
    //output: 333--- 3 3
}

从输出结果可以看出,使用三参数方式时,截取后的slice的cap将会重新设置。如果第二个参数和第三个参数相同,那么截取后的slice的len==cap,这样在执行append的时候一定会重新分配数组,从而保证原始的数组(nums)不会发生变化。

<完结>

<script type="text/javascript"> $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text().split('\n').length; var $numbering = $('<ul/>').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('<li/>').text(i)); }; $numbering.fadeIn(1700); }); }); </script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值