[:]切片是 Go 中最基础的数据结构,之前我们谈过切片传递、切换转换、切片扩容等内容。
本文,我们将探讨切片拷贝,就切片的三种拷贝方式进行图解分析,希望帮助读者巩固一下基础知识。
深浅拷贝
所谓深浅拷贝,其实都是进行复制,主要区别在于复制出来的新对象和原来的对象,它们的数据发生改变时,是否会相互影响。
简单而言,B 复制 A,如果 A 的数据发生变化,B 也跟着变化,这是浅拷贝。反之, 如果 B 不发生变化,则为深拷贝。
深浅拷贝差异的根本原因在于,复制出来的对象与原对象是否会指向同一个地址。
以下是 Python 中 list 与 Go 中 slice 深浅拷贝的表现差异
// Python 版
if __name__ == '__main__':
    a = [1, 2, 3]
    b = a
    c = a[:]
    a[0] = 100
    print(a, b, c) // [100, 2, 3] [100, 2, 3] [1, 2, 3]
// Golang 版
func main() {
 a := []int{1, 2, 3}
 b := a
 c := a[:]
 a[0] = 100
 fmt.Println(a, b, c) // [100 2 3] [100 2 3] [100 2 3]
}[:]= 拷贝
=func main() {
 a := []int{1, 2, 3}
 b := a
 fmt.Println(unsafe.Pointer(&a))  // 0xc00000c030
 fmt.Println(a, &a[0])            // [100 2 3] 0xc00001a078
 fmt.Println(unsafe.Pointer(&b))  // 0xc00000c048
 fmt.Println(b, &b[0])            // [100 2 3] 0xc00001a078
}图解

[:] 拷贝
[:]func main() {
 a := []int{1, 2, 3}
 b := a[:]
 fmt.Println(unsafe.Pointer(&a)) // 0xc0000a4018
 fmt.Println(a, &a[0])           // [1 2 3] 0xc0000b4000
 fmt.Println(unsafe.Pointer(&b)) // 0xc0000a4030
 fmt.Println(b, &b[0])           // [1 2 3] 0xc0000b4000
}图解

[start: end]b:=a[1:]
copy() 拷贝
copy()copy()func copy(dst, src []Type) int其返回值代表切片中被拷贝的元素个数
func main() {
 a := []int{1, 2, 3}
 b := make([]int, len(a), len(a))
 copy(b, a)
 fmt.Println(unsafe.Pointer(&a))  // 0xc00000c030
 fmt.Println(a, &a[0])            // [1 2 3] 0xc00001a078
 fmt.Println(unsafe.Pointer(&b))  // 0xc00000c048
 fmt.Println(b, &b[0])            // [1 2 3] 0xc00001a090
}图解

copy 的元素数量与原始切片和目标切片的大小、容量有关系
func main() {
 a := []int{1, 2, 3}
 b := []int{-1, -2, -3, -4}
 copy(b, a)
 fmt.Println(unsafe.Pointer(&a))  // 0xc0000a4018
 fmt.Println(a, &a[0])            // [1 2 3] 0xc0000b4000
 fmt.Println(unsafe.Pointer(&b))  // 0xc0000a4030
 fmt.Println(b, &b[0])            // [1 2 3 -4] 0xc0000aa060
}图解

总结
切片是 Go 语言中最基本的数据结构,它的扩容与拷贝细节,在理解不当时,是很容易写出程序 bug 的。
=[:]copy()=[:]copy()感谢你的点赞和在看哦~

