跳到主要内容
Go 语言 Slice 深拷贝与浅拷贝详解 | 极客日志
Go / Golang
Go 语言 Slice 深拷贝与浅拷贝详解 深入解析 Go 语言切片(slice)的内存结构与拷贝机制。涵盖浅拷贝(共享底层数组)与深拷贝(独立副本)的区别、实现方式(赋值、copy、append)、常见陷阱(初始化、扩容分离)及实际应用场景(函数传参、并发、缓存)。通过代码示例对比性能与安全性,提供最佳实践建议,帮助开发者避免数据污染并优化内存使用。
DebugKing 发布于 2026/3/29 更新于 2026/5/27 27 浏览前言
在 Go 语言中,切片(slice)是使用最频繁的数据结构之一。然而,很多开发者对切片的拷贝操作存在误解,特别是深拷贝和浅拷贝的区别。不当的拷贝操作可能导致难以追踪的 bug 和数据不一致问题。本文将深入探讨 slice 的拷贝机制,通过详细的代码示例和流程图,帮助你彻底理解深拷贝和浅拷贝的本质区别。
一、切片的基本概念回顾
1.1 切片的内部结构
在深入讨论拷贝之前,我们需要先理解切片的内部结构。切片在 Go 语言中是一个引用类型,其内部由三部分组成:
type slice struct {
array unsafe.Pointer
len int
cap int
}
内存布局示意图 :
切片变量: ┌─────────────────┐ │ array ptr │──────┐ ├─────────────────┤ │ │ len : 5 │ │ ├─────────────────┤ │ │ cap : 5 │ │ └─────────────────┘ │ ▼ ┌─────┬─────┬─────┬─────┬─────┐ │ 0 │ 1 │ 2 │ 3 │ 4 │ └─────┴─────┴─────┴─────┴─────┘ 底层数组(连续内存)
1.2 切片的创建方式
package main
import "fmt"
func main () {
s1 := []int {1 , 2 , 3 , 4 , 5 }
s2 := make ([]int , 5 , 10 )
arr := [ ] { , , , , }
s3 := arr[ : ]
fmt.Printf( , (s1), (s1), s1)
fmt.Printf( , (s2), (s2), s2)
fmt.Printf( , (s3), (s3), s3)
}
5
int
1
2
3
4
5
1
4
"s1: len=%d, cap=%d, %v\n"
len
cap
"s2: len=%d, cap=%d, %v\n"
len
cap
"s3: len=%d, cap=%d, %v\n"
len
cap
二、浅拷贝(Shallow Copy)
2.1 什么是浅拷贝? 浅拷贝是指只复制切片本身(切片头),而不复制底层数组。新切片和原切片共享同一个底层数组,修改其中一个会影响另一个。
2.2 浅拷贝的实现方式 package main
import "fmt"
func main () {
original := []int {1 , 2 , 3 , 4 , 5 }
fmt.Printf("原始切片:%v, 地址:%p\n" , original, &original)
shallowCopy := original
fmt.Printf("浅拷贝:%v, 地址:%p\n" , shallowCopy, &shallowCopy)
fmt.Printf("\n原始底层数组地址:%p\n" , original)
fmt.Printf("浅拷贝底层数组地址:%p\n" , shallowCopy)
shallowCopy[0 ] = 100
fmt.Printf("\n修改后原始切片:%v\n" , original)
fmt.Printf("修改后浅拷贝:%v\n" , shallowCopy)
}
原始切片:[1 2 3 4 5] , 地址:0 xc000010030 浅拷贝:[1 2 3 4 5] , 地址:0 xc000010048 原始底层数组地址:&[1 2 3 4 5] 浅拷贝底层数组地址:&[1 2 3 4 5] 修改后原始切片:[100 2 3 4 5] 修改后浅拷贝:[100 2 3 4 5]
原始切片:┌──────────────┐ │ array: 0x123 │─────┐ │ len: 5 │ │ │ cap: 5 │ │ └──────────────┘ │ ▼ 浅拷贝:┌─────┬─────┬─────┬─────┬─────┐ ┌──────────────┐ │ 100 │ 2 │ 3 │ 4 │ 5 │ │ array: 0x123 │──┼─▶ (共享同一个底层数组) │ len: 5 │ │ └─────┴─────┴─────┴─────┴─────┘ │ cap: 5 │ │ 0x123 └──────────────┘ │ │ │ │
package main
import "fmt"
func main () {
original := []int {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 }
subSlice := original[2 :6 ]
fmt.Printf("原始切片:%v\n" , original)
fmt.Printf("子切片:%v\n" , subSlice)
fmt.Printf("原始底层数组:%p\n" , original)
fmt.Printf("子切片底层数组:%p\n" , subSlice)
subSlice[0 ] = 999
fmt.Printf("\n修改后原始切片:%v\n" , original)
fmt.Printf("修改后子切片:%v\n" , subSlice)
fmt.Printf("子切片容量:%d\n" , cap (subSlice))
}
2.3 浅拷贝的特性总结 package main
import "fmt"
func demonstrateShallowCopy () {
fmt.Println("=== 浅拷贝特性演示 ===" )
original := []string {"A" , "B" , "C" , "D" , "E" }
copy1 := original
copy2 := original[1 :4 ]
fmt.Printf("原始指针:%p\n" , original)
fmt.Printf("copy1 指针:%p\n" , copy1)
fmt.Printf("copy2 指针:%p\n" , copy2)
copy1[0 ] = "X"
fmt.Printf("修改后原始:%v\n" , original)
copy1 = append (copy1, "F" )
copy1[0 ] = "Y"
fmt.Printf("追加后原始:%v\n" , original)
fmt.Printf("追加后 copy1:%v\n" , copy1)
fmt.Printf("copy2 长度:%d, 容量:%d\n" , len (copy2), cap (copy2))
fmt.Printf("原始长度:%d, 容量:%d\n" , len (original), cap (original))
}
开始:创建原始切片 s │ ▼ ┌─────────────────────────────────┐ │ 底层数组:[1] [2] [3] [4] [5] │ │ ↑ │ └─────────────────────────────────┘ │ ├──► 浅拷贝 1 := s │ │ │ ▼ │ ┌──────────────┐ │ │ array: 同 s │───┐ │ │ len: 5 │ │ │ │ cap: 5 │ │ │ └──────────────┘ │ │ │ ├──► 浅拷贝 2 := s[1:4] │ │ │ │ │ ▼ │ │ ┌──────────────┐ │ │ │ array: s[1] │───┼─┐ │ │ len: 3 │ │ │ │ │ cap: 4 │ │ │ │ └──────────────┘ │ │ │ │ │ │ ▼ ▼ │ ┌─────────────────┐ │ │ [1] [2] [3] [4] [5] │ │ └─────────────────┘ │ 共享 │ └──► 修改浅拷贝 1[0] = 100 │ ▼ 影响所有共享该位置的切片
三、深拷贝(Deep Copy)
3.1 什么是深拷贝? 深拷贝是指创建一个全新的切片,包括新的底层数组,并复制原切片的所有元素。新切片和原切片完全独立,修改一个不会影响另一个。
3.2 深拷贝的实现方式 package main
import "fmt"
func main () {
original := []int {1 , 2 , 3 , 4 , 5 }
fmt.Printf("原始切片:%v, 地址:%p\n" , original, &original)
deepCopy := make ([]int , len (original))
copied := copy (deepCopy, original)
fmt.Printf("深拷贝:%v, 地址:%p\n" , deepCopy, &deepCopy)
fmt.Printf("复制了 %d 个元素\n" , copied)
fmt.Printf("\n原始底层数组:%p\n" , original)
fmt.Printf("深拷贝底层数组:%p\n" , deepCopy)
deepCopy[0 ] = 100
fmt.Printf("\n修改后原始切片:%v\n" , original)
fmt.Printf("修改后深拷贝:%v\n" , deepCopy)
}
原始切片:[1 2 3 4 5] , 地址:0 xc000010030 深拷贝:[1 2 3 4 5] , 地址:0 xc000010048 复制了 5 个元素 原始底层数组:&[1 2 3 4 5] 深拷贝底层数组:&[1 2 3 4 5] 修改后原始切片:[1 2 3 4 5] 修改后深拷贝:[100 2 3 4 5]
原始切片:┌──────────────┐ │ array: 0x123 │─────┐ │ len: 5 │ │ │ cap: 5 │ │ └──────────────┘ │ ▼ ┌─────┬─────┬─────┬─────┬─────┐ │ 1 │ 2 │ 3 │ 4 │ 5 │ └─────┴─────┴─────┴─────┴─────┘ 0x123 深拷贝:┌──────────────┐ │ array: 0x456 │─────┐ │ len: 5 │ │ │ cap: 5 │ │ └──────────────┘ │ ▼ ┌─────┬─────┬─────┬─────┬─────┐ │ 1 │ 2 │ 3 │ 4 │ 5 │ (复制后的新数组) └─────┴─────┴─────┴─────┴─────┘ 0x456
package main
import "fmt"
func main () {
original := []int {1 , 2 , 3 , 4 , 5 }
var deepCopy []int
deepCopy = append (deepCopy, original...)
fmt.Printf("原始:%v, 地址:%p\n" , original, original)
fmt.Printf("深拷贝:%v, 地址:%p\n" , deepCopy, deepCopy)
deepCopy[0 ] = 100
fmt.Printf("修改后原始:%v\n" , original)
fmt.Printf("修改后深拷贝:%v\n" , deepCopy)
}
package main
import "fmt"
func main () {
original := []int {1 , 2 , 3 , 4 , 5 }
deepCopy := make ([]int , len (original))
for i := 0 ; i < len (original); i++ {
deepCopy[i] = original[i]
}
fmt.Printf("原始:%v, 地址:%p\n" , original, original)
fmt.Printf("深拷贝:%v, 地址:%p\n" , deepCopy, deepCopy)
}
3.3 copy 函数的详细用法 package main
import "fmt"
func main () {
fmt.Println("=== copy 函数的各种用法 ===" )
src := []int {1 , 2 , 3 , 4 , 5 }
dst := make ([]int , 3 )
n := copy (dst, src)
fmt.Printf("复制 %d 个元素:%v\n" , n, dst)
dst2 := make ([]int , 5 )
n = copy (dst2, src[1 :4 ])
fmt.Printf("复制部分:%v\n" , dst2)
dst3 := make ([]int , 10 )
n = copy (dst3, src)
fmt.Printf("复制到更大切片:%v (剩余为零值)\n" , dst3)
s := []int {1 , 2 , 3 , 4 , 5 }
copy (s[1 :], s[2 :])
fmt.Printf("重叠复制:%v\n" , s)
str := "Hello"
bytes := make ([]byte , len (str))
copy (bytes, str)
fmt.Printf("字符串到字节:%v -> %s\n" , bytes, bytes)
src2 := []int {1 , 2 , 3 }
dst4 := make ([]int , 2 )
n = copy (dst4, src2)
fmt.Printf("返回值:复制了 %d 个元素\n" , n)
}
四、深拷贝与浅拷贝的对比
4.1 对比表格 特性 浅拷贝 深拷贝 底层数组 共享 独立 内存占用 小(只复制切片头) 大(复制整个数据) 性能 快 慢(需要复制数据) 修改影响 互相影响 互不影响 实现方式 直接赋值、切片操作 copy、append、循环 适用场景 只读操作、需要共享数据 需要独立副本、防止修改
4.2 代码对比示例 package main
import (
"fmt"
"time"
)
func compareCopyMethods () {
data := make ([]int , 1000000 )
for i := range data {
data[i] = i
}
start := time.Now()
shallow := data
shallowTime := time.Since(start)
start = time.Now()
deep1 := make ([]int , len (data))
copy (deep1, data)
deepTime1 := time.Since(start)
start = time.Now()
deep2 := append ([]int {}, data...)
deepTime2 := time.Since(start)
start = time.Now()
deep3 := make ([]int , len (data))
for i := 0 ; i < len (data); i++ {
deep3[i] = data[i]
}
deepTime3 := time.Since(start)
fmt.Printf("浅拷贝时间:%v\n" , shallowTime)
fmt.Printf("深拷贝 (copy) 时间:%v\n" , deepTime1)
fmt.Printf("深拷贝 (append) 时间:%v\n" , deepTime2)
fmt.Printf("深拷贝 (循环) 时间:%v\n" , deepTime3)
shallow[0 ] = 999
fmt.Printf("浅拷贝修改后原数据:%d\n" , data[0 ])
deep1[0 ] = 888
fmt.Printf("深拷贝修改后原数据:%d\n" , data[0 ])
}
func main () {
compareCopyMethods()
}
4.3 内存地址验证 package main
import (
"fmt"
"unsafe"
)
func verifyMemoryAddress () {
fmt.Println("=== 内存地址验证 ===" )
original := []string {"A" , "B" , "C" }
shallow := original
deep := make ([]string , len (original))
copy (deep, original)
getDataPtr := func (s []string ) uintptr {
return *(*uintptr )(unsafe.Pointer(&s))
}
fmt.Printf("原始底层数组地址:0x%x\n" , getDataPtr(original))
fmt.Printf("浅拷贝底层数组地址:0x%x\n" , getDataPtr(shallow))
fmt.Printf("深拷贝底层数组地址:0x%x\n" , getDataPtr(deep))
shallow[0 ] = "X"
fmt.Printf("浅拷贝修改后原始:%v\n" , original)
deep[0 ] = "Y"
fmt.Printf("深拷贝修改后原始:%v\n" , original)
}
五、实际应用场景
5.1 场景 1:函数参数传递 package main
import "fmt"
func processSliceBad (s []int ) {
s[0 ] = 999
s = append (s, 100 )
}
func processSliceGood (s []int ) []int {
result := make ([]int , len (s))
copy (result, s)
result[0 ] = 999
result = append (result, 100 )
return result
}
func main () {
data := []int {1 , 2 , 3 , 4 , 5 }
fmt.Println("原始数据:" , data)
processSliceBad(data)
fmt.Println("错误处理后:" , data)
data = []int {1 , 2 , 3 , 4 , 5 }
result := processSliceGood(data)
fmt.Println("正确处理后原数据:" , data)
fmt.Println("正确处理后结果:" , result)
}
5.2 场景 2:并发处理 package main
import (
"fmt"
"sync"
)
func parallelProcess (data []int ) [][]int {
numWorkers := 4
chunkSize := len (data) / numWorkers
var wg sync.WaitGroup
results := make ([][]int , numWorkers)
for i := 0 ; i < numWorkers; i++ {
wg.Add(1 )
go func (workerID int ) {
defer wg.Done()
start := workerID * chunkSize
end := start + chunkSize
if workerID == numWorkers-1 {
end = len (data)
}
chunk := make ([]int , end-start)
copy (chunk, data[start:end])
for j := range chunk {
chunk[j] *= 2
}
results[workerID] = chunk
}(i)
}
wg.Wait()
return results
}
func main () {
data := make ([]int , 100 )
for i := range data {
data[i] = i
}
results := parallelProcess(data)
fmt.Printf("原数据前 10 个:%v\n" , data[:10 ])
fmt.Printf("结果前 10 个:%v\n" , results[0 ][:10 ])
}
5.3 场景 3:缓存系统 package main
import (
"fmt"
"sync"
"time"
)
type Cache struct {
mu sync.RWMutex
data map [string ][]int
}
func NewCache () *Cache {
return &Cache{
data: make (map [string ][]int ),
}
}
func (c *Cache) Get(key string ) []int {
c.mu.RLock()
defer c.mu.RUnlock()
if val, ok := c.data[key]; ok {
result := make ([]int , len (val))
copy (result, val)
return result
}
return nil
}
func (c *Cache) Set(key string , value []int ) {
c.mu.Lock()
defer c.mu.Unlock()
copyVal := make ([]int , len (value))
copy (copyVal, value)
c.data[key] = copyVal
}
func (c *Cache) Update(key string , fn func ([]int ) []int ) {
c.mu.Lock()
defer c.mu.Unlock()
if val, ok := c.data[key]; ok {
newVal := fn(val)
copyVal := make ([]int , len (newVal))
copy (copyVal, newVal)
c.data[key] = copyVal
}
}
func main () {
cache := NewCache()
original := []int {1 , 2 , 3 , 4 , 5 }
cache.Set("key1" , original)
cached := cache.Get("key1" )
cached[0 ] = 999
fmt.Printf("原始数据:%v\n" , original)
fmt.Printf("缓存数据:%v\n" , cache.Get("key1" ))
fmt.Printf("修改后的副本:%v\n" , cached)
}
5.4 场景 4:矩阵操作 package main
import "fmt"
type Matrix [][]int
func (m Matrix) DeepCopy() Matrix {
if m == nil {
return nil
}
copyMatrix := make (Matrix, len (m))
for i := range m {
if m[i] == nil {
copyMatrix[i] = nil
continue
}
copyMatrix[i] = make ([]int , len (m[i]))
copy (copyMatrix[i], m[i])
}
return copyMatrix
}
func (m Matrix) Transpose() Matrix {
if len (m) == 0 {
return m
}
rows, cols := len (m), len (m[0 ])
result := make (Matrix, cols)
for i := range result {
result[i] = make ([]int , rows)
}
for i := 0 ; i < rows; i++ {
for j := 0 ; j < cols; j++ {
result[j][i] = m[i][j]
}
}
return result
}
func (m Matrix) SafeTranspose() Matrix {
copyM := m.DeepCopy()
return copyM.Transpose()
}
func main () {
original := Matrix{{1 , 2 , 3 }, {4 , 5 , 6 }, {7 , 8 , 9 }}
fmt.Println("原始矩阵:" )
printMatrix(original)
transposed := original.Transpose()
fmt.Println("\n转置后的矩阵:" )
printMatrix(transposed)
fmt.Println("原始矩阵被修改了:" )
printMatrix(original)
original = Matrix{{1 , 2 , 3 }, {4 , 5 , 6 }, {7 , 8 , 9 }}
safeTransposed := original.SafeTranspose()
fmt.Println("\n安全转置后的矩阵:" )
printMatrix(safeTransposed)
fmt.Println("原始矩阵保持不变:" )
printMatrix(original)
}
func printMatrix (m Matrix) {
for _, row := range m {
fmt.Println(row)
}
}
六、高级主题
6.1 多维切片的深拷贝 package main
import "fmt"
func DeepCopy2D (src [][]int ) [][]int {
if src == nil {
return nil
}
dst := make ([][]int , len (src))
for i := range src {
if src[i] == nil {
dst[i] = nil
continue
}
dst[i] = make ([]int , len (src[i]))
copy (dst[i], src[i])
}
return dst
}
func DeepCopy3D (src [][][]int ) [][][]int {
if src == nil {
return nil
}
dst := make ([][][]int , len (src))
for i := range src {
if src[i] == nil {
dst[i] = nil
continue
}
dst[i] = make ([][]int , len (src[i]))
for j := range src[i] {
if src[i][j] == nil {
dst[i][j] = nil
continue
}
dst[i][j] = make ([]int , len (src[i][j]))
copy (dst[i][j], src[i][j])
}
}
return dst
}
func main () {
matrix := [][]int {{1 , 2 , 3 }, {4 , 5 , 6 }, {7 , 8 , 9 }}
copyMatrix := DeepCopy2D(matrix)
copyMatrix[0 ][0 ] = 999
fmt.Println("原始二维切片:" )
print2D(matrix)
fmt.Println("\n副本二维切片:" )
print2D(copyMatrix)
}
func print2D (s [][]int ) {
for _, row := range s {
fmt.Println(row)
}
}
6.2 包含指针的切片深拷贝 package main
import "fmt"
type Person struct {
Name string
Age int
Tags []string
}
func (p *Person) DeepCopy() *Person {
if p == nil {
return nil
}
copy := &Person{
Name: p.Name,
Age: p.Age,
}
if p.Tags != nil {
copy .Tags = make ([]string , len (p.Tags))
copy (copy .Tags, p.Tags)
}
return copy
}
func main () {
original := &Person{
Name: "张三" ,
Age: 30 ,
Tags: []string {"go" , "developer" , "backend" },
}
shallowCopy := original
deepCopy := original.DeepCopy()
fmt.Printf("原始:%+v, Tags 地址:%p\n" , original, original.Tags)
fmt.Printf("浅拷贝:%+v, Tags 地址:%p\n" , shallowCopy, shallowCopy.Tags)
fmt.Printf("深拷贝:%+v, Tags 地址:%p\n" , deepCopy, deepCopy.Tags)
shallowCopy.Tags[0 ] = "python"
deepCopy.Tags[1 ] = "fullstack"
fmt.Printf("\n修改后原始:%+v\n" , original)
fmt.Printf("修改后深拷贝:%+v\n" , deepCopy)
}
6.3 性能优化技巧 package main
import (
"fmt"
"time"
)
func BatchDeepCopy (src [][]int ) [][]int {
if len (src) == 0 {
return nil
}
totalElements := 0
for i := range src {
totalElements += len (src[i])
}
dst := make ([][]int , len (src))
data := make ([]int , totalElements)
offset := 0
for i := range src {
dst[i] = data[offset : offset+len (src[i])]
copy (dst[i], src[i])
offset += len (src[i])
}
return dst
}
func comparePerformance () {
size := 1000
src := make ([][]int , size)
for i := range src {
src[i] = make ([]int , size)
for j := range src[i] {
src[i][j] = i*size + j
}
}
start := time.Now()
dst1 := make ([][]int , size)
for i := range src {
dst1[i] = make ([]int , len (src[i]))
copy (dst1[i], src[i])
}
normalTime := time.Since(start)
start = time.Now()
dst2 := BatchDeepCopy(src)
optimizedTime := time.Since(start)
fmt.Printf("普通深拷贝耗时:%v\n" , normalTime)
fmt.Printf("优化深拷贝耗时:%v\n" , optimizedTime)
fmt.Printf("性能提升:%.2f 倍\n" , float64 (normalTime)/float64 (optimizedTime))
}
func main () {
comparePerformance()
}
七、常见陷阱和注意事项
7.1 陷阱 1:copy 函数的目标切片必须已初始化 package main
import "fmt"
func main () {
src := []int {1 , 2 , 3 }
var dst1 []int
copy (dst1, src)
fmt.Printf("错误复制:%v (长度:%d)\n" , dst1, len (dst1))
dst2 := make ([]int , len (src))
copy (dst2, src)
fmt.Printf("正确复制:%v\n" , dst2)
dst3 := append ([]int {}, src...)
fmt.Printf("append 复制:%v\n" , dst3)
}
7.2 陷阱 2:copy 函数只复制 min(len(dst), len(src)) 个元素 package main
import "fmt"
func main () {
src := []int {1 , 2 , 3 , 4 , 5 }
dst1 := make ([]int , 3 )
n1 := copy (dst1, src)
fmt.Printf("复制了 %d 个元素:%v\n" , n1, dst1)
dst2 := make ([]int , 10 )
n2 := copy (dst2, src)
fmt.Printf("复制了 %d 个元素:%v\n" , n2, dst2)
}
7.3 陷阱 3:切片扩容后的分离 package main
import "fmt"
func main () {
original := []int {1 , 2 , 3 }
shallow := original
fmt.Println("=== 扩容前 ===" )
fmt.Printf("original: %v, 地址:%p\n" , original, original)
fmt.Printf("shallow: %v, 地址:%p\n" , shallow, shallow)
original = append (original, 4 , 5 , 6 )
fmt.Println("\n=== 扩容后 ===" )
fmt.Printf("original: %v, 地址:%p\n" , original, original)
fmt.Printf("shallow: %v, 地址:%p\n" , shallow, shallow)
original[0 ] = 999
fmt.Printf("修改 original 后 original: %v\n" , original)
fmt.Printf("修改 original 后 shallow: %v\n" , shallow)
}
7.4 陷阱 4:循环变量捕获问题 package main
import "fmt"
func main () {
slices := [][]int {{1 }, {2 }, {3 }}
copies := make ([]*[]int , len (slices))
for i, s := range slices {
copies[i] = &s
}
fmt.Println("错误捕获:" )
for _, cp := range copies {
fmt.Printf("%v " , **cp)
}
fmt.Println()
correctCopies := make ([]*[]int , len (slices))
for i := range slices {
copy := make ([]int , len (slices[i]))
copy [0 ] = slices[i][0 ]
correctCopies[i] = ©
}
fmt.Println("正确捕获:" )
for _, cp := range correctCopies {
fmt.Printf("%v " , **cp)
}
fmt.Println()
}
八、最佳实践总结
8.1 选择指南 需求 推荐方式 原因 只需要读取数据 浅拷贝 性能好,内存占用小 需要修改但不想影响原数据 深拷贝(copy) 安全可靠 快速创建副本 深拷贝(append) 代码简洁 多维切片 递归深拷贝 确保所有层级独立 大量小切片 批量分配优化 减少内存分配次数
8.2 完整工具包 package sliceutil
import "reflect"
func DeepCopy (src interface {}) interface {} {
if src == nil {
return nil
}
srcVal := reflect.ValueOf(src)
srcType := srcVal.Type()
dstVal := reflect.New(srcType).Elem()
deepCopyRecursive(srcVal, dstVal)
return dstVal.Interface()
}
func deepCopyRecursive (src, dst reflect.Value) {
switch src.Kind() {
case reflect.Slice:
if src.IsNil() {
return
}
dst.Set(reflect.MakeSlice(src.Type(), src.Len(), src.Cap()))
for i := 0 ; i < src.Len(); i++ {
deepCopyRecursive(src.Index(i), dst.Index(i))
}
case reflect.Array:
for i := 0 ; i < src.Len(); i++ {
deepCopyRecursive(src.Index(i), dst.Index(i))
}
case reflect.Map:
if src.IsNil() {
return
}
dst.Set(reflect.MakeMap(src.Type()))
for _, key := range src.MapKeys() {
srcVal := src.MapIndex(key)
dstVal := reflect.New(srcVal.Type()).Elem()
deepCopyRecursive(srcVal, dstVal)
dst.SetMapIndex(key, dstVal)
}
case reflect.Ptr:
if src.IsNil() {
return
}
dstVal := reflect.New(src.Elem().Type())
deepCopyRecursive(src.Elem(), dstVal.Elem())
dst.Set(dstVal)
case reflect.Interface:
if src.IsNil() {
return
}
srcVal := src.Elem()
dstVal := reflect.New(srcVal.Type()).Elem()
deepCopyRecursive(srcVal, dstVal)
dst.Set(dstVal)
default :
dst.Set(src)
}
}
func CopySlice [T any ](src []T) []T {
if src == nil {
return nil
}
dst := make ([]T, len (src))
copy (dst, src)
return dst
}
func Copy2DSlice [T any ](src [][]T) [][]T {
if src == nil {
return nil
}
dst := make ([][]T, len (src))
for i := range src {
if src[i] == nil {
dst[i] = nil
continue
}
dst[i] = make ([]T, len (src[i]))
copy (dst[i], src[i])
}
return dst
}
func CopyIf [T any ](src []T, predicate func (T) bool ) []T {
result := make ([]T, 0 , len (src))
for _, v := range src {
if predicate(v) {
result = append (result, v)
}
}
return result
}
func SafeAppend [T any ](src []T, elems ...T) []T {
dst := make ([]T, len (src)+len (elems))
copy (dst, src)
copy (dst[len (src):], elems)
return dst
}
8.3 使用示例 package main
import (
"fmt"
"yourmodule/sliceutil"
)
func main () {
original := []int {1 , 2 , 3 , 4 , 5 }
copy1 := sliceutil.CopySlice(original)
evens := sliceutil.CopyIf(original, func (n int ) bool {
return n%2 == 0
})
extended := sliceutil.SafeAppend(original, 6 , 7 , 8 )
matrix := [][]int {{1 , 2 }, {3 , 4 }}
matrixCopy := sliceutil.Copy2DSlice(matrix)
fmt.Println("原始:" , original)
fmt.Println("副本:" , copy1)
fmt.Println("偶数:" , evens)
fmt.Println("扩展:" , extended)
fmt.Println("矩阵副本:" , matrixCopy)
}
总结
1. 核心概念理解
浅拷贝 :只复制切片头,共享底层数组
深拷贝 :复制完整的底层数组,创建独立副本
2. 实现方式
浅拷贝:newSlice := oldSlice
深拷贝:newSlice := make([]T, len(oldSlice)); copy(newSlice, oldSlice)
3. 性能考虑
浅拷贝:O(1) 时间复杂度,固定内存开销
深拷贝:O(n) 时间复杂度,内存开销与数据大小成正比
4. 适用场景
浅拷贝适用 :
只读操作
需要共享数据
性能敏感且数据量大
临时视图操作
深拷贝适用 :
5. 最佳实践
func chooseCopyMethod (data []int ) {
view := data
independent := make ([]int , len (data))
copy (independent, data)
func processReadOnly (s []int ) {
}
func processModify (s []int ) []int {
result := make ([]int , len (s))
copy (result, s)
return result
}
}
理解深拷贝和浅拷贝的区别,不仅能避免常见的编程错误,还能帮助我们设计出更安全、更高效的代码。在实际开发中,要根据具体需求选择合适的拷贝方式,在性能和安全性之间找到平衡点。
相关免费在线工具 Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
JSON 压缩 通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
JSON美化和格式化 将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online