go 深拷贝发生在什么情况下?切片的深拷贝是怎么做的?

本文阅读 3 分钟
首页 golang 正文
题目序号:(225、2462、4794、6617)
频次:4
题目来源:映客,腾讯,北京合链

答案1:(小小)+

深拷贝,浅拷贝概念

  1. 深拷贝(Deep Copy):

拷贝的是数据本身,创造一个样的新对象,新创建的对象与原对象不共享内存,新创建的对象在内存中开辟一个新的内存地址,新对象值修改时不会影响原对象值。既然内存地址不同,释放内存地址时,可分别释放。

  1. 浅拷贝(Shallow Copy):

拷贝的是数据地址,只复制指向的对象的指针,此时新对象和老对象指向的内存地址是一样的,新对象值修改时老对象也会变化。释放内存地址时,同时释放内存地址。参考来源
在go语言中值类型赋值都是深拷贝,引用类型一般都是浅拷贝:

  • 值类型的数据,默认全部都是深拷贝:Array、Int、String、Struct、Float,Bool
  • 引用类型的数据,默认全部都是浅拷贝:Slice,Map

对于引用类型,想实现深拷贝,不能直接 := ,而是要先开辟地址空间(new) ,再进行赋值。

怎么进行(切片的)深拷贝?

可以使用 copy() 函数来进行深拷贝,copy 不会进行扩容,当要复制的 slice 比原 slice 要大的时候,只会移除多余的。

func main() {
    slice1 := []int{1, 2, 3, 4, 5}
    slice2 := []int{6, 7, 8}

    copy(slice2, slice1) // 复制slice1的前3个元素到slice2中
    fmt.Println(slice1, slice2)
    copy(slice1, slice2) // 复制slice2的3个元素到slice1的前3个位置
    fmt.Println(slice1, slice2)
}

使用 append() 函数来进行深拷贝,append 会进行扩容(这里涉及到的就是 Slice 的扩容机制 )。

func main() {
    a := []int{1, 2, 3}
    b := make([]int, 0)
    b = append(b, a[:]...)
    fmt.Println(a, b)
    a[1] = 1000
    fmt.Println(a, b)
    fmt.Printf("%p,%p", a, b)
}

Go 中切片扩容的策略:

  • 首先判断,如果新申请容量大于 2 倍的旧容量,最终容量就是新申请的容 量
  • 否则判断,如果旧切片的长度小于 1024,则最终容量就是旧容量的两倍
  • 否则判断,如果旧切片长度大于等于 1024,则最终容量从旧容量开始循环 增加原来的 1/4, 直到最终容量大于等于新申请的容量
  • 如果最终容量计算值溢出,则最终容量就是新申请容量

注意:如果 slice 在 append() 过程中没有发生扩容,那么修改就在原来的内存中,如果发生了扩容,就修改在新的内存中。

本文来自投稿,不代表本站立场,如若转载,请注明出处:
Golang Map 如何扩容
« 上一篇 09-17
go什么场景使用接口
下一篇 » 09-17

发表评论

发表评论