The pitfalls of Go slice replication-the underlying array reallocates memory and size

Slicing brings many problems. For performance reasons, slicing a slice will not copy the underlying array . This means that the sub-slices of the slice just follow the view of the original slice changes.


Therefore, if you want to separate it from the initial slice, don't forget to use copy(from_slice, to_slice).


For the append function, forgetting to copy() becomes even more dangerous:
if the original slice does not have enough capacity to hold the new value, the underlying array will reallocate memory and size. This means that whether the result of append can point to the original array depends on its initial capacity. This can lead to uncertain bugs that are hard to find.


In the code below, we see that the effect of appending a value to a sub-slice depends on the capacity of the original slice:

import "fmt"

// 切片是引用传递
func doStuff(value []string) {
    
    
	fmt.Printf("value=%v\n", value)

	value2 := value[:]
	value2 = append(value2, "b", "c", "d")
	fmt.Printf("value=%v, value2=%v\n", value, value2)

	value2[0] = "1"
	value2[1] = "2"
	fmt.Printf("value=%v, value2=%v\n", value, value2)
}

func main() {
    
    
	slice1 := []string{
    
    "a"} // 长度 1, 容量 1
	doStuff(slice1)
	// Output:
	// value=[a] -- ok
	// value=[a], value2=[a b c d] -- ok: value 未改变, value2 被更新
	// value=[a], value2=[1 2 c d] -- ok: value 未改变, value2 被更新
	// 原因:slice1容量不够,value2利用append添加元素后,value2的底层数组将会重新分配内存和大小(与slice1内存地址不同)

	slice10 := make([]string, 1, 10) // 长度 1, 容量 10
	slice10[0] = "a"
	doStuff(slice10)
	// Output:
	// value=[a] -- ok
	// value=[a], value2=[a b c d] -- ok: value 未改变, value2 被更新
	// value=[1], value2=[1 2 c d] -- value 改变了???
	// 原因:slice10容量充足,value2利用append添加元素后,value2的底层数组不会重新分配内存和大小,与(与slice10内存地址相同)
}

Guess you like

Origin blog.csdn.net/QiuHaoqian/article/details/108996719