前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >面试官:深拷贝,浅拷贝讲解下

面试官:深拷贝,浅拷贝讲解下

作者头像
小锟哥哥
发布2024-04-01 18:35:39
1020
发布2024-04-01 18:35:39
举报
文章被收录于专栏:GoLang全栈GoLang全栈

当涉及到数据的复制时,理解深拷贝和浅拷贝的概念及其区别非常重要。

下面我将更详细地解释深拷贝和浅拷贝,并提供更多示例以帮助您更好地理解。

1. 深拷贝与浅拷贝的概念

  • 浅拷贝:浅拷贝只复制数据的顶层结构,而不会递归复制数据中的引用类型数据。因此,如果原始数据包含引用类型的字段(如切片、映射、指针等),则浅拷贝将只复制它们的引用,而不会复制引用指向的实际数据。这意味着修改拷贝后的对象中的引用类型数据会影响原始对象中的数据。
  • 深拷贝:深拷贝会递归地复制所有的数据,包括引用类型的数据。这意味着创建的拷贝是完全独立于原始对象的,修改拷贝后的对象不会影响原始对象。

2. 浅拷贝示例

代码语言:javascript
复制
goCopy code
package main

import "fmt"

type Person struct {
 Name   string
 Age    int
 Colors []string
}

func main() {
 // 原始对象
 p1 := Person{
  Name:   "Alice",
  Age:    30,
  Colors: []string{"red", "blue", "green"},
 }

 // 浅拷贝
 p2 := p1

 // 修改 p2 中的引用类型数据
 p2.Colors[0] = "yellow"

 // p1 中的引用类型数据也被修改了
 fmt.Println(p1.Colors) // 输出: [yellow blue green]
}

3. 深拷贝示例

代码语言:javascript
复制
goCopy code
package main

import (
 "fmt"
 "reflect"
)

type Person struct {
 Name   string
 Age    int
 Colors []string
}

func deepCopy(src, dst interface{}) {
 srcValue := reflect.ValueOf(src)
 dstValue := reflect.ValueOf(dst)

 if srcValue.Kind() != reflect.Ptr || dstValue.Kind() != reflect.Ptr {
  fmt.Println("参数必须是指针类型")
  return
 }

 if srcValue.Elem().Type() != dstValue.Elem().Type() {
  fmt.Println("源对象和目标对象类型不匹配")
  return
 }

 dstValue.Elem().Set(srcValue.Elem())
}

func main() {
 // 原始对象
 p1 := &Person{
  Name:   "Alice",
  Age:    30,
  Colors: []string{"red", "blue", "green"},
 }

 // 深拷贝
 var p2 Person
 deepCopy(p1, &p2)

 // 修改 p2 中的引用类型数据
 p2.Colors[0] = "yellow"

 // p1 中的引用类型数据不受影响
 fmt.Println(p1.Colors) // 输出: [red blue green]
}

在深拷贝示例中,我们通过反射实现了一个通用的深拷贝函数,可以用于任意类型的结构体。

3.拷贝问题在go语言中的表现

在 Go 语言中,变量赋值时的拷贝行为可以根据变量类型的不同而有所不同。以下是常见类型变量赋值时使用的是浅拷贝或深拷贝的列表:

3.1. 浅拷贝

  • 数组:数组的赋值是进行浅拷贝的,即将数组的值复制给另一个数组,但是如果数组元素是引用类型(如切片),则只会复制引用,而不会复制引用指向的数据。
  • 结构体:结构体的赋值也是进行浅拷贝的,即将结构体的字段值逐个复制给另一个结构体,但如果结构体字段中包含引用类型,则只会复制引用。
代码语言:javascript
复制
package main

import "fmt"

type Person struct {
 Name string
 Age  int
}

func main() {
 // 定义原始切片
 slice1 := []int{1, 2, 3, 4, 5}

 // 浅拷贝切片
 slice2 := slice1

 // 修改拷贝后的切片
 slice2[0] = 10

 // 原始切片也被修改了
 fmt.Println(slice1) // 输出: [10 2 3 4 5]
}

在这个示例中,**slice2** 是对 slice1 的浅拷贝,修改 slice2 的元素也会影响到 **slice1**。

3.2. 深拷贝

  • 切片:切片的赋值是进行深拷贝的,即会复制切片的元素以及底层数组,而不仅仅是复制切片的引用。
  • Map:Map 的赋值是进行深拷贝的,即会复制 map 中的键值对,但是如果键或值是引用类型,则只会复制引用,而不会复制引用指向的数据。

其他类型的变量赋值通常也是进行浅拷贝的,但需要注意复合类型中包含的引用类型数据的拷贝行为。如果需要进行深拷贝,可以通过编写相应的函数或方法来实现。

代码语言:javascript
复制
package main

import "fmt"

type Person struct {
 Name string
 Age  int
}

func main() {
 // 定义原始切片
 slice1 := []int{1, 2, 3, 4, 5}

 // 使用 make 函数创建一个新的切片并复制原始切片的内容
 slice2 := make([]int, len(slice1))
 copy(slice2, slice1)

 // 修改拷贝后的切片
 slice2[0] = 10

 // 原始切片不受影响
 fmt.Println(slice1) // 输出: [1 2 3 4 5]
}

在这个示例中,我们使用 copy 函数创建了一个新的切片 **slice2**,并将 slice1 的内容复制到了 slice2 中,这样就实现了深拷贝。修改 slice2 不会影响到 **slice1**。

3.3. 总结

  • 浅拷贝只复制数据的顶层结构,而深拷贝会递归地复制所有数据。
  • 使用浅拷贝时,修改拷贝后的对象中的引用类型数据会影响原始对象中的数据,而深拷贝则不会出现这种情况。
  • 在进行数据复制时,根据需求选择合适的方式,以确保数据的正确性和独立性。
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-03-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 GoLang全栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 深拷贝与浅拷贝的概念
  • 2. 浅拷贝示例
  • 3. 深拷贝示例
  • 3.拷贝问题在go语言中的表现
    • 3.1. 浅拷贝
      • 3.2. 深拷贝
        • 3.3. 总结
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档