本文转载自微信公众号「Golang技术分享」,看完拷贝作者机器铃砍菜刀 。期图切片转载本文请联系Golang技术分享公众号。解别
在刚使用 Go 时,再搞菜刀曾将 Python 深拷贝手法[:]用于 Go 中 ,不清结果造成了 bug。看完拷贝相信不少转语言的期图切片 Gopher 也在切片拷贝上栽过跟头。
切片是解别 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] }发现没有?在 Go 中 [:] 操作并不是深拷贝。
通过=操作符拷贝切片,这是浅拷贝。
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()函数签名如下
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()拷贝是深拷贝。
这样的图解方式,高防服务器你喜欢吗~