go
- 在go语言中值类型赋值都是深拷贝,引用类型一般都是浅拷贝
- 其本质就是,深拷贝会拷贝数据,而浅拷贝只会拷贝内存的地址,所有就会出现,像slice那样修改底层数组的值,slice的值也跟着改动。
深拷贝
修改a的值b不变,说明是值的拷贝
func main() {
var a = 123
b := a
fmt.Println(a, b)
a = 456
fmt.Println(a, b)
}
浅拷贝
修改a的值,b的值也跟着修改了,原因是两个slice指向同一个内存地址,所以得出记录slice拷贝是浅拷贝
func main() {
a := []int{1, 2, 3}
b := a
fmt.Println(a, b)
a[0] = 1000
fmt.Println(a, b)
}
slice深拷贝
可以通过内置的copy函数实现,或append导致扩容形成一个新的切片
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)
}
func main() {
slice1 := []int{1, 2, 3, 4, 5}
slice2 := []int{5, 4, 3}
copy(slice2, slice1) // 只会复制slice1的前3个元素到slice2中
fmt.Println(slice1, slice2)
copy(slice1, slice2) // 只会复制slice2的3个元素到slice1的前3个位置
fmt.Println(slice1, slice2)
}
总结
-
赋值操作:
- 如果是值类型,就会产生深拷贝
- 如果是引用类型,就会产生浅拷贝
-
深浅拷贝的区别:
- 深拷贝:光拷贝值,地址不相关。拷贝结束两变量互不影响。
- 浅拷贝:拷贝地址。两变量指向同一地址。拷贝结束也相关,改变一个,另一个也跟着变。
python
有点小不同:
- 对于不可变类型:不论深浅拷贝,都是引用。
- 浅拷贝:只复制最外层的结构,除最外层其余的直接将其地址引用过来。
- 深拷贝:全部数据/结构都进行复制,(除不可变类型)增大数据独立性 ,如果深拷贝中,只要发现复制数据中有一个不是不可变类型就重新创建。
from copy import deepcopy, copy
def echo_addr(interface):
return hex(id(interface))
def init():
# 赋值
l1 = [1, 2, 3]
l2 = l1
print(echo_addr(l1), echo_addr(l2))
# 0x2ca7d68e600 0x2ca7d68e600
print(echo_addr(l1[0]), echo_addr(l2[0]))
# 0x7ff8b3451710 0x7ff8b3451710
l2[0] = 5
print(l1, l2)
# [5, 2, 3] [5, 2, 3]
def cp():
# 浅拷贝
l1 = [1, 2, 3]
l2 = copy(l1)
print(echo_addr(l1), echo_addr(l2))
# 0x2950198e700 0x2950198e540
print(echo_addr(l1[0]), echo_addr(l2[0]))
# 0x7ff8b3451710 0x7ff8b3451710
l2[0] = 5
print(l1, l2)
# [1, 2, 3] [5, 2, 3]
def deep_cp():
# 深拷贝
l1 = [1, 2, 3]
l2 = deepcopy(l1)
print(echo_addr(l1), echo_addr(l2))
# 0x2059c9ce740 0x2059c9ce580
print(echo_addr(l1[0]), echo_addr(l2[0]))
# 0x7ff8b3451710 0x7ff8b3451710
l2[0] = 5
print(l1, l2)
# [1, 2, 3] [5, 2, 3]
# init()
# cp()
deep_cp()
def cpcpcpcpcp():
a = 1
b = copy(a)
c = deepcopy(a)
print(echo_addr(a), echo_addr(b), echo_addr(c))
# 0x7ff88bce1710 0x7ff88bce1710 0x7ff88bce1710
# cpcpcpcpcp()