要想搞明白深拷贝和浅拷贝的区别,我们需要先弄懂以下几点:
Go 语言里面变量有两类,一类是值类型,一类是引用类型。
两者区别是什么呢?
我们在电脑里面创建的变量,都是需要内存来存放的。
值变量就是直接,一个内存地址对应一个值。
而引用变量,则是某个值存放的是另一个值的地址。
我画了一个逻辑图,帮助我们去理解这个概念。
在 Go 语言中:
而我们提到的深拷贝和浅拷贝,则指的是引用类型的值处理方案。
浅拷贝指的是,把变量里面存的内存地址拷贝了,所指向的真实值并没拷贝。
像下面这张图:
0x004 浅拷贝到了 0x003 里面,实际上只是拷贝了一个 0x006 这个内存地址。
代码是怎么实现的呢?
func main() {
a := []string{"1","2","3"}
b := a
fmt.Println("a:",a)
fmt.Println("b:",b)
}
//执行结果
$ go run cp.go
a: [1 2 3]
b: [1 2 3]
怎么去证明是浅拷贝呢?
我们现在去改变下 a 切片里面的值:
func main() {
a := []string{"1","2","3"}
b := a
a[0]="ko"
fmt.Println("a:",a)
fmt.Println("b:",b)
}
//执行结果
$ go run cp.go
a: [ko 2 3]
b: [ko 2 3]
你会发现我改了 a 里面的值,b 里面的值同样被改了。
Go 的底层,slice 他其实是一个特殊的结构体,他包含三个字段:
// A notInHeapSlice is a slice backed by go:notinheap memory.
type notInHeapSlice struct {
array *notInHeap
len int
cap int
}
这个数组里面的 array 才是真实数组值的存放地址。
在 Go 里面我们只需要使用 copy 即可:
func main() {
a := []string{"1","2","3"}
// 初始化一个空数组
b := make([]string,len(a),cap(a))
copy(b, a)
a[0]="ko"
fmt.Println("a:",a)
fmt.Println("b:",b)
}
//执行结果
$ go run cp.go
a: [ko 2 3]
b: [1 2 3]
我们在初始化 b 数组的时候,我们需要指定数组的长度和容量,你可以直接 b := make([]string, 3)
但是我们并不建议这样去写。
这样我们创建出来的 b ,就是独立的一个数组切片了。
你学废了么?