浅拷贝复制值类型字段和引用地址,深拷贝递归复制所有数据;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"
这就是浅拷贝带来的副作用:两个结构体共享同一份引用数据。要避免这种情况,就需要实现深拷贝——递归复制所有层级的数据,确保新旧结构体完全独立。
最直接的方式是为结构体编写一个自定义的复制方法,手动复制每个字段,特别是处理引用类型。
继续上面的例子:
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没有内置深拷贝机制,正是为了让你明确意识到数据共享的风险。通过自定义复制函数,你能精确控制复制行为,写出更健壮的程序。
# git
# go
# github
# golang
# go语言
# 区别
# 结构体
# 递归
# 循环
# 指针
# 值类型
# 引用类型
相关栏目:
【
Google疑问12 】
【
Facebook疑问10 】
【
网络优化76771 】
【
技术知识130152 】
【
IDC云计算60162 】
【
营销推广131313 】
【
AI优化88182 】
【
百度推广37138 】
【
网站推荐60173 】
【
精选阅读31334 】
相关推荐:
php嵌入式多设备通信怎么实现_php同时管理多个串口设备【操作】
Win11怎么关闭系统透明度_Windows11个性化颜色透明效果
Windows系统被恶意软件破坏后的恢复策略_错误提示修复方式
Win10电脑C盘红了怎么清理_Windows10系统盘深度瘦身指南
Windows10系统怎么查看显卡型号_Win10 dxdiag显示选项卡
php控制舵机角度怎么调_php发送pwm信号控制舵机转动【解答】
C#如何使用Channel C#通道实现异步通信
Win11任务栏怎么调到左边_Win11开始菜单居左设置教程【步骤】
c++获取当前时间戳_c++ time函数使用详解
php怎么捕获异常_trycatch结构处理运行时错误的技巧【方法】
mac本地php环境如何开启curl_curl扩展启用与测试步骤详解【汇总】
Win11怎么激活Windows10_Win11激活Win10系统方法【步骤】
如何使用Golang安装依赖库_管理模块和第三方包
LINUX下如何配置VLAN虚拟局域网_在LINUX交换机与服务器上的实现
PythonPandas数据分析项目教程_时间序列透视表应用
Windows10如何删除Windows.old_Win10磁盘清理系统文件选项
如何在 Go 中正确反序列化多个同级 XML 元素(而非单个根节点)
c# 如何深拷贝和浅拷贝
MySQL 中使用 IF 和 CASE 实现查询字段条件化显示
Go 语言标准库为何不提供泛型 Contains 方法:设计哲学与类型系统约束
Win11怎么关闭自动修复_跳过Win11开机自动修复循环【技巧】
Win11怎么设置多显示器任务栏 Win11扩展任务栏至多屏方便跨屏操作【技巧】
Mac上的iMovie如何剪辑视频?(新手入门教程)
Windows 11怎么设置默认解压软件_Windows 11为ZIP/RAR文件指定默认打开程序
windows如何禁用驱动程序强制签名_windows高级启动设置指南
c++如何利用doxygen生成开发文档_c++ 代码注释规范与HTML文档导出【案例】
Win10怎么卸载鲁大师_Win10彻底卸载鲁大师方法【步骤】
Windows10如何查看蓝屏日志_Win10使用事件查看器分析Dump文件
MAC怎么用连续互通相机里的“桌上视角”_MAC在视频通话中同时展示人脸和桌面
Win11怎么设置屏保时间_调整Win11屏幕保护等待时间【详解】
c++中的Tag Dispatching是什么_c++利用标签分发优化函数重载【元编程】
Windows10怎么用“讲述人”读屏辅助 Windows10轻松使用开启讲述人朗读屏幕文字帮助视障用户【教程】
如何使用Golang进行HTTP服务性能测试_测量吞吐量和延迟
Win11如何设置文件关联 Win11修改特定文件类型的默认打开程序【详解】
Win10怎么更改用户名 Win10修改账户名称操作教程
Windows笔记本无法进入睡眠模式怎么办?(电源疑难解答)
Win11开机速度慢怎么优化_Win11系统启动加速设置指南【方法】
如何在Golang中使用container/heap实现堆_Golang container/heap最小堆方法
LINUX怎么设置系统语言_LINUX修改中文环境
Win10怎么设置开机密码_Windows10账户登录密码设置与取消
MAC怎么解压RAR格式文件_MAC第三方解压工具安装与压缩包管理【教程】
Go 中实现 Python urllib.quote() 功能的等效方法
c++如何用AFL++进行模糊测试 c++ Fuzzing入门【安全】
Windows 10怎么录屏_Windows 10使用Xbox Game Bar录制屏幕视频教程
Win11无法安装软件怎么办_Win11解除应用安装限制设置【修复】
Win11怎么设置开机密码_Windows11账户登录选项PIN码
Linux如何使用Curl发送请求_Linux下API接口测试与文件下载技巧【步骤】
如何处理“XML格式不正确”错误 常见XML well-formed问题解决方法
Win10怎样设置多显示器_Win10多显示器扩展设置【攻略】
如何更改Windows资源管理器的默认启动位置?(快速访问/此电脑)
2025-11-12
致胜网络推广营销网专注海外推广十年,是谷歌推广.Facebook广告全球合作伙伴,我们精英化的技术团队为企业提供谷歌海外推广+外贸网站建设+网站维护运营+Google SEO优化+社交营销为您提供一站式海外营销服务。