浅拷贝复制值类型字段和引用地址,深拷贝递归复制所有数据;Go默认浅拷贝,需手动实现深拷贝以避免共享引用问题。

在Go语言中,结构体的拷贝分为浅拷贝和深拷贝。理解它们的区别以及如何实现深拷贝,对编写安全、可维护的代码至关重要。
当你直接赋值一个结构体变量时,Go默认执行的是浅拷贝。这意味着基本类型字段会被复制值,但指针、切片、map、channel等引用类型字段只会复制其“引用”,而不是底层数据。
例如:
type User struct {
Name string
Tags []string
}
u1 := User{Name: "Alice", Tags: []string{"go", "dev"}}
u2 := u1 // 浅拷贝
u2.Tags[0] = "rust"
// 此时 u1.Tags[0] 也会变成 "rust"
这就是浅拷贝带来的副作用:两个结构体共享同一份引用数据。要避免这种情况,就需要实现深拷贝——递归复制所有层级的数据,确保新旧结构体完全独立。
立即学习“go语言免费学习笔记(深入)”;
最直接的方式是为结构体编写一个自定义的复制方法,手动复制每个字段,特别是处理引用类型。
继续上面的例子:
func (u *User) DeepCopy() *User {
if u == nil {
return nil
}
var tagsCopy []string
if u.Tags != nil {
tagsCopy = make([]string, len(u.Tags))
copy(tagsCopy, u.Tags)
}
return &User{
Name: u.Name,
Tags: tagsCopy,
}
}
使用方式:
u2 := u1.DeepCopy() u2.Tags[0] = "rust" // u1 不受影响
这种方法清晰可控,适合字段不多、结构简单的场景。你还可以根据需要决定是否复制nil字段,或对嵌套结构体递归调用其DeepCopy方法。
如果结构体包含其他结构体或指针字段,深拷贝逻辑需要逐层展开。
示例:
type Profile struct {
Age int
City string
}
type User struct {
Name string
Tags []string
Profile *Profile
}
func (u *User) DeepCopy() *User {
if u == nil {
return nil
}
var tagsCopy []string
if u.Tags != nil {
tagsCopy = make([]string, len(u.Tags))
copy(tagsCopy, u.Tags)
}
var profileCopy *Profile
if u.Profile != nil {
profileCopy = &Profile{
Age: u.Profile.Age,
City: u.Profile.City,
}
}
return &User{
Name: u.Name,
Tags: tagsCopy,
Profile: profileCopy,
}
}
每一层引用类型都需要独立复制,确保不共享原始数据。
深拷贝不是万能的,使用时要注意以下几点:
github.com/mohae/deepcopy等库,但要评估依赖和安全性。基本上就这些。Go没有内置深拷贝机制,正是为了让你明确意识到数据共享的风险。通过自定义复制函数,你能精确控制复制行为,写出更健壮的程序。
以上就是如何理解Golang中结构体的深拷贝_Golang自定义复制函数实现的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号