Goスライスレプリケーションの落とし穴-基になる配列はメモリとサイズを再割り当てします

スライスには多くの問題があります。パフォーマンス上の理由から、スライスをスライスしても、基になる配列はコピーされませんこれは、スライスのサブスライスが元のスライス変更のビューに従うことを意味します。


したがって、最初のスライスから分離する場合は、copy(from_slice、to_slice)を使用することを忘れないでください。


追加関数の場合、copy()を忘れると、さらに危険になり
ます。元のスライスに新しい値を保持するのに十分な容量がない場合、基になる配列はメモリとサイズを再割り当てします。これは、追加の結果が元の配列を指すことができるかどうかは、その初期容量に依存することを意味します。これは、見つけるのが難しい不確実なバグにつながる可能性があります。


以下のコードでは、サブスライスに値を追加する効果は、元のスライスの容量に依存することがわかります。

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内存地址相同)
}

おすすめ

転載: blog.csdn.net/QiuHaoqian/article/details/108996719