问题描述:
在开发xx需求时,要将一结构体切片完整的复制一份,然后修改其中某几个变量值,修改完后发现原结构体切片也被修改了。
package main
type Label struct {
Name string `json:"labelName"`
Value string `json:"labelValue"`
}
func main(){
a := []Label{
{"aa", "aa-value"},
{"bb", "bb-value"},
}
b := a
b[0].Name = "cc"
fmt.Println(a)
fmt.Println(b)
}
// 打印如下
// 修改 b[0]后影响到了 a
[{cc aa-value} {bb bb-value}]
[{cc aa-value} {bb bb-value}]
问题原因:
go语言中切片的底层数据结构由三部分组成,分别是指向底层数组的指针、长度和容量。其中,指向底层数组的指针用于定位切片的起始位置,长度表示切片中实际存储的元素个数,容量表示切片可以容纳的最大元素个数,如下所示:
type slice struct {
array unsafe.Pointer
len int
cap int
}
所以使用普通的赋值方式,slice struct中的 array 只是复制了一下指针给新的变量,新指针指向的地址仍旧跟原指针一样,所以修改新数据能影响到原数据。
问题修改:
-
- 使用 append 复制新副本
package main
type Label struct {
Name string `json:"labelName"`
Value string `json:"labelValue"`
}
func main(){
a := []Label{
{"aa", "aa-value"},
{"bb", "bb-value"},
}
// 等价于 append([]Label{}, a...)
// []Label(nil) 表示新建一个长度为0的空切片
// 赋值整段代码等价于 d := make([]Label, 0);d = append(d, a...)
c := append([]Label(nil), a...)
c[0].Name = "cc"
fmt.Println(a)
fmt.Println(c)
}
// 打印如下
[{aa aa-value} {bb bb-value}]
[{cc aa-value} {bb bb-value}]
-
- 使用 copy 复制新副本
d := make([]Label, len(a))
copy(d, a)