Go语言拷贝切片后修改副本却影响原切片问题求助
指针切片拷贝后修改副本影响原切片的问题解决
问题场景
想要实现拷贝切片、修改副本元素值后将副本追加到原切片,但运行代码后发现原切片元素也被修改,实际输出与预期不符。
原代码:
import "fmt" type Item struct { name string number int } func main() { names := []string{"a", "b"} numbers := []int{1, 2} items := []*Item{} for _, name := range names { item := &Item{name: name} items = append(items, item) } for n, i := range numbers { if n > 0 { fmt.Println(n, "make a copy of the items") itemCopies := make([]*Item, len(items)) copy(itemCopies, items) fmt.Println(n, "set the numbers on the copies") for _, item := range itemCopies { item.number = i } fmt.Println(n, "append the copies to the original") items = append(items, itemCopies...) } else { fmt.Println(n, "first pass set all the items to the first number") for _, item := range items { item.number = i } } } for n, i := range items { fmt.Printf("%d %+v\n", n, *i) } }
实际输出:
0 {name:a number:2} 1 {name:b number:2} 2 {name:a number:2} 3 {name:b number:2}
预期输出:
0 {name:a number:1} 1 {name:b number:1} 2 {name:a number:2} 3 {name:b number:2}
问题根源
你的切片类型是[]*Item,切片中存储的是指向Item结构体的指针。使用copy(itemCopies, items)时,只是把原切片里的指针值复制到了新切片中——原切片和副本切片的指针指向的是同一个Item结构体实例。当你修改副本中指针指向的number字段时,本质是修改了同一个结构体的内容,原切片的指针自然会读到修改后的值。
解决方案
需要对每个Item进行深度拷贝,也就是为每个元素创建新的Item结构体实例,而不是仅复制指针。修改拷贝逻辑后的完整代码:
import "fmt" type Item struct { name string number int } func main() { names := []string{"a", "b"} numbers := []int{1, 2} items := []*Item{} for _, name := range names { item := &Item{name: name} items = append(items, item) } for n, i := range numbers { if n > 0 { fmt.Println(n, "make a copy of the items") // 替换原copy逻辑,创建新的Item实例 itemCopies := make([]*Item, len(items)) for idx, item := range items { itemCopies[idx] = &Item{ name: item.name, number: item.number, } } fmt.Println(n, "set the numbers on the copies") for _, item := range itemCopies { item.number = i } fmt.Println(n, "append the copies to the original") items = append(items, itemCopies...) } else { fmt.Println(n, "first pass set all the items to the first number") for _, item := range items { item.number = i } } } for n, i := range items { fmt.Printf("%d %+v\n", n, *i) } }
运行后输出符合预期:
0 {name:a number:1} 1 {name:b number:1} 2 {name:a number:2} 3 {name:b number:2}
内容的提问来源于stack exchange,提问作者Jonathan Kittell
相关产品推荐
相关产品推荐

