导读:本期聚焦于小伙伴创作的《如何使用Golang实现结构体拷贝?浅拷贝和深拷贝方法示例》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何使用Golang实现结构体拷贝?浅拷贝和深拷贝方法示例》有用,将其分享出去将是对创作者最好的鼓励。

在Golang项目开发过程中,结构体是承载业务数据的重要类型,很多时候我们需要复制一个结构体的实例,这时候就会涉及到浅拷贝和深拷贝两种操作方式,两者的核心差异在于是否复制结构体内部引用类型指向的底层数据。

如何使用Golang实现结构体拷贝?浅拷贝和深拷贝方法示例

浅拷贝的实现方式

浅拷贝是最简单的结构体拷贝方式,它会直接复制结构体的所有字段值,如果字段是值类型,就会复制对应的值,如果字段是引用类型,只会复制引用地址,不会复制引用指向的实际数据。

直接赋值实现浅拷贝

Golang中结构体直接赋值默认就是浅拷贝,代码示例如下:

package main

import "fmt"

// 定义包含引用类型的结构体
type User struct {
	Name   string
	Age    int
	Hobbies []string // 切片是引用类型
}

func main() {
	// 初始化原始结构体
	originUser := User{
		Name:    "张三",
		Age:     20,
		Hobbies: []string{"篮球", "跑步"},
	}

	// 直接赋值实现浅拷贝
	copiedUser := originUser

	// 修改拷贝结构体的引用类型字段
	copiedUser.Hobbies[0] = "足球"

	fmt.Println("原始用户爱好:", originUser.Hobbies)
	fmt.Println("拷贝用户爱好:", copiedUser.Hobbies)
}

运行上述代码可以看到,修改copiedUserHobbies字段后,originUserHobbies也发生了变化,这是因为两个结构体的Hobbies字段指向了同一个底层切片。

使用copy函数实现部分浅拷贝

如果只需要复制结构体的部分字段,也可以使用copy函数处理切片类型的字段,但本质还是浅拷贝:

package main

import "fmt"

type Product struct {
	ID    int
	Tags  []string
}

func main() {
	p1 := Product{ID: 1, Tags: []string{"电子", "数码"}}
	p2 := Product{ID: p1.ID}
	// 复制切片引用,属于浅拷贝
	p2.Tags = p1.Tags

	p2.Tags[0] = "家电"
	fmt.Println(p1.Tags) // 输出 [家电 数码]
}

深拷贝的实现方式

深拷贝会完整复制结构体的所有层级数据,包括引用类型指向的底层数据,修改拷贝后的结构体不会影响原始结构体,常见的实现方式有以下几种。

手动递归复制实现深拷贝

对于结构简单明确的结构体,可以手动逐字段复制,遇到引用类型就重新创建并复制内容:

package main

import "fmt"

type Address struct {
	City  string
	Street string
}

type Employee struct {
	Name    string
	Addr    Address
	Skills  []string
}

// 手动实现深拷贝函数
func DeepCopyEmployee(origin Employee) Employee {
	copyEmp := Employee{
		Name: origin.Name,
		// 值类型直接复制
		Addr: Address{
			City:  origin.Addr.City,
			Street: origin.Addr.Street,
		},
	}
	// 重新创建切片并复制内容
	copyEmp.Skills = make([]string, len(origin.Skills))
	copy(copyEmp.Skills, origin.Skills)
	return copyEmp
}

func main() {
	originEmp := Employee{
		Name: "李四",
		Addr: Address{City: "北京", Street: "长安街"},
		Skills: []string{"Go", "Java"},
	}

	copiedEmp := DeepCopyEmployee(originEmp)
	// 修改拷贝后的引用类型字段
	copiedEmp.Addr.City = "上海"
	copiedEmp.Skills[0] = "Python"

	fmt.Println("原始员工地址:", originEmp.Addr.City)
	fmt.Println("拷贝员工地址:", copiedEmp.Addr.City)
	fmt.Println("原始员工技能:", originEmp.Skills)
	fmt.Println("拷贝员工技能:", copiedEmp.Skills)
}

运行上述代码可以看到,修改拷贝后的结构体的引用类型字段,不会影响原始结构体的对应字段,实现了完全的深拷贝。

使用encoding包序列化反序列化实现深拷贝

如果结构体字段较多或者结构复杂,手动复制会比较繁琐,可以利用Golang的序列化机制实现通用深拷贝:

package main

import (
	"bytes"
	"encoding/gob"
	"fmt"
)

type Order struct {
	OrderID int
	Items   []string
	Extra   map[string]string
}

// 通用深拷贝函数,利用gob序列化反序列化
func DeepCopyByGob(origin interface{}, target interface{}) error {
	var buf bytes.Buffer
	// 序列化原始对象
	enc := gob.NewEncoder(&buf)
	if err := enc.Encode(origin); err != nil {
		return err
	}
	// 反序列化到目标对象
	dec := gob.NewDecoder(&buf)
	return dec.Decode(target)
}

func main() {
	originOrder := Order{
		OrderID: 1001,
		Items:   []string{"手机", "耳机"},
		Extra:   map[string]string{"discount": "9折"},
	}

	var copiedOrder Order
	err := DeepCopyByGob(originOrder, &copiedOrder)
	if err != nil {
		fmt.Println("深拷贝失败:", err)
		return
	}

	// 修改拷贝后的数据
	copiedOrder.Items[0] = "平板"
	copiedOrder.Extra["discount"] = "8折"

	fmt.Println("原始订单商品:", originOrder.Items)
	fmt.Println("拷贝订单商品:", copiedOrder.Items)
	fmt.Println("原始订单额外信息:", originOrder.Extra)
	fmt.Println("拷贝订单额外信息:", copiedOrder.Extra)
}

这种方式不需要手动处理每个字段,适合复杂结构体的深拷贝,但性能会比手动复制稍差,因为涉及序列化和反序列化的开销。

两种拷贝方式的对比

我们可以通过表格对比浅拷贝和深拷贝的差异:

对比项浅拷贝深拷贝
复制范围仅复制结构体顶层字段值复制所有层级的数据
引用类型处理只复制引用地址复制引用指向的底层数据
修改影响修改拷贝的引用类型会影响原始对象修改拷贝对象不会影响原始对象
性能性能高,开销小性能较低,开销大
适用场景结构体无引用类型或不需要隔离引用数据需要完全隔离原始和拷贝对象的数据

注意事项

  • 如果结构体包含sync.Mutex等不可序列化的字段,使用序列化方式实现深拷贝会失败,需要手动处理这类字段。
  • 浅拷贝适合临时使用、不需要修改引用类型数据的场景,能减少不必要的内存开销。
  • 深拷贝如果结构体嵌套层级很深,手动实现容易遗漏字段,建议优先使用序列化方式或者第三方成熟的深拷贝库。
  • 拷贝结构体时需要注意字段的导出性,非导出字段在序列化反序列化时无法被复制,会导致数据丢失。

Golang结构体拷贝浅拷贝深拷贝修改时间:2026-07-14 08:27:31

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。