copy函数 | Go
copy函数格式如下,仅接受切片类型的参数。其中 srcSlice 为数据来源切片,destSlice 为复制的目标(也就是将 srcSlice 复制到 destSlice),来源和目标的类型必须一致,copy() 函数的返回值表示实际发生复制的元素个数。
copy( destSlice, srcSlice []T) int
那么数组能拷贝到切片吗? 由于copy来源和目标的类型必须一致,因此需要使用[:]
操作将数组转为切片。
array4 := [4]int{4, -4, 4, -4}
s6 := []int{1, -1, 1, -1, -5, 5}
copy(s6, array4[0:])
fmt.Println("s6:", s6) //s6: [4 -4 4 -4 -5 5]
查看copy的源码,copy()会先计算 dst 的长度 l=len(dst),再计算**复制长度 n=min(len(src), l)**。拷贝为为深拷贝,将src切片指向底层数组中的值拷贝到dst切片指向的数组中,针对dst切片进行的操作不会对src产生任何的影响。
// runtime/slice.go
// slicecopy is used to copy from a string or slice of pointerless elements into a slice.
func slicecopy(toPtr unsafe.Pointer, toLen int, fromPtr unsafe.Pointer, fromLen int, width uintptr) int {
if fromLen == 0 || toLen == 0 {
return 0
}
n := fromLen
if toLen < n {
n = toLen
}
if width == 0 {
return n
}
size := uintptr(n) * width
if raceenabled {
callerpc := getcallerpc()
pc := abi.FuncPCABIInternal(slicecopy)
racereadrangepc(fromPtr, size, callerpc, pc)
racewriterangepc(toPtr, size, callerpc, pc)
}
if msanenabled {
msanread(fromPtr, size)
msanwrite(toPtr, size)
}
if asanenabled {
asanread(fromPtr, size)
asanwrite(toPtr, size)
}
if size == 1 { // common case worth about 2x to do here
// TODO: is this still worth it with new memmove impl?
*(*byte)(toPtr) = *(*byte)(fromPtr) // known to be a byte pointer
} else {
memmove(toPtr, fromPtr, size)
}
return n
}
copy使用:这里将 s1 切片中的 3 个元素复制到 s2 中,n 返回复制的元素个数 3。s4 的长度只有 2,所以只复制了 s3 的前 2 个元素,n 返回 2。slice1的长度为0,因此复制长度为0,输出[]。
s1 := []int{1, 2, 3}
s2 := make([]int, 10)
n := copy(s2, s1)
fmt.Println(s1, s2, n) // [1 2 3] [1 2 3 0 0 0 0 0 0 0] 3
s3 := []int{1, 2, 3}
s4 := make([]int, 2)
n = copy(s4, s3)
fmt.Println(s3, s4, n) // [1 2 3] [1 2] 2
slice1 := make([]int,0,3)
slice2 := []int{6, 7, 8, 9}
copy(slice1, slice2)
fmt.Println(slice1) //[]
再查看如下代码:
package main
import "fmt"
func main() {
src := []int{1, 2, 3, 4, 5}
dst := make([]int, 5)
numberOfElementsCopied := copy(dst, src)
fmt.Printf("Number Of Elements Copied: %d\n", numberOfElementsCopied)
fmt.Printf("dst: %v\n", dst)
fmt.Printf("src: %v\n", src)
//After changing dst
dst[0] = 10
fmt.Println("\nAfter changing dst")
fmt.Printf("dst: %v\n", dst)
fmt.Printf("src: %v\n", src)
//Length of destination is less than length of source
dst = make([]int, 4)
numberOfElementsCopied = copy(dst, src)
fmt.Println("\nLength of dst less than src")
fmt.Printf("Number Of Elements Copied: %d\n", numberOfElementsCopied)
fmt.Printf("dst: %v\n", dst)
fmt.Printf("src: %v\n", src)
//Length of destination is greater than length of source
dst = make([]int, 6)
numberOfElementsCopied = copy(dst, src)
fmt.Println("\nLength of dst less than src")
fmt.Printf("Number Of Elements Copied: %d\n", numberOfElementsCopied)
fmt.Printf("dst: %v\n", dst)
fmt.Printf("src: %v\n", src)
}
输出为:
Number Of Elements Copied: 5
dst: [1 2 3 4 5]
src: [1 2 3 4 5]
After changing dst
dst: [10 2 3 4 5]
src: [1 2 3 4 5]
Length of dst less than src
Number Of Elements Copied: 4
dst: [1 2 3 4]
src: [1 2 3 4 5]
Length of dst less than src
Number Of Elements Copied: 5
dst: [1 2 3 4 5 0]
src: [1 2 3 4 5]
参考资料:
Copy function in Go (Golang)
golang Slice的创建、添加、删除等操作和源码分析
版权声明:本博客所有文章除特别声明外,均采用 CC BY 4.0许可协议,转载请注明出处
本文链接:https://blog.redamancy.tech/technique/41