golang append的坑

最近在使用golang append的时候,发现了一个坑,特意记录一下,下面是例子:

	var a = []int32{1, 2, 3, 4, 5}
	var b = append(a[:1], a[2:]...)
	fmt.Println(a)		// [1 3 4 5 5]
	fmt.Println(b)		// [1 3 4 5]

想当然的觉得操作b进行append不会影响到a,但是结果却影响到了,于是我又特意看了下append的源码:

// The append built-in function appends elements to the end of a slice. If
// it has sufficient capacity, the destination is resliced to accommodate the
// new elements. If it does not, a new underlying array will be allocated.
// Append returns the updated slice. It is therefore necessary to store the
// result of append, often in the variable holding the slice itself:
//
//	slice = append(slice, elem1, elem2)
//	slice = append(slice, anotherSlice...)
//
// As a special case, it is legal to append a string to a byte slice, like this:
//
//	slice = append([]byte("hello "), "world"...)
func append(slice []Type, elems ...Type) []Type {
	m := len(slice)
	n := m + len(elems)
	if n > cap(slice) {
		// 扩容逻辑
		// Grow slice
		newcap := cap(slice)
		doublecap := newcap + newcap
		if doublecap < n {
			newcap = n
		} else {
			if old := len(slice); old < 1024 {
				newcap = doublecap
			} else {
				// Check 0 < newcap to detect overflow
				// and prevent an infinite loop.
				for 0 < newcap && newcap < n {
					newcap += newcap / 4
				}
				// Set newcap to the new capacity, doubling
				// it if that's what occurred.
				if newcap <= 0 {
					newcap = n
				}
			}
		}
		newslice := make([]Type, n, newcap)
		copy(newslice, slice)
		slice = newslice
	}
	slice = slice[0:n]
	copy(slice[m:n], elems)
	return slice
}

总的来说,就是判断对象是否append之后的长度是否超过它本身的cap,超过就扩容,不超过就是用之前的切片,并且新加的元素会覆盖之前的元素,也就是这个

slice = slice[0:n]
copy(slice[m:n], elems)

所以才会导致a的值发生了变化,为此我对a和b的切片地址和数组地址进行了打印,结果符合预期

var a = []int32{1, 2, 3, 4, 5}
var b = append(a[:1], a[2:]...)
fmt.Printf("切片地址:%p,长度:%v,容量:%v,添加元素长度:%v\n", &a, len(a[:1]), cap(a[:1]), len(a[2:]))
fmt.Printf("切片地址:%p\n", &b)
// 获取切片底层数组的地址
fmt.Printf("数组地址:%p\n", &a[0])
fmt.Printf("数组地址:%p\n", &b[0])

// 终端打印
切片地址:0xc000008db0,长度:1,容量:5,添加元素长度:3
切片地址:0xc000008dc8
数组地址:0xc00001e738
数组地址:0xc00001e738

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值