之前用 copy 不多,本以為它是個(gè)很方便的函數(shù),沒(méi)想到在做練習(xí)題時(shí)竟還是被它坑了。是我對(duì)他期望太多了。
func copy(dst, src []Type) int
基本認(rèn)識(shí):
- 它只能用于切片,不能用于 map 等任何其他類(lèi)型
- 它返回結(jié)果為一個(gè) int 型值,表示 copy 的長(zhǎng)度
坑位一:切片 dst 需要先初始化長(zhǎng)度
不是你定義好類(lèi)型,就能將 src 完全 copy 到 dst 的,你需要初始化長(zhǎng)度。
- 如果 dst 長(zhǎng)度小于 src 的長(zhǎng)度,則 copy 部分;
- 如果大于,則全部拷貝過(guò)來(lái),只是沒(méi)占滿(mǎn) dst 的坑位而已;
- 相等時(shí)剛好不多不少 copy 過(guò)來(lái)。
坑位二:源切片中元素類(lèi)型為引用類(lèi)型時(shí),拷貝的是引用
由于只 copy 切片中的元素,所以如果切片元素的類(lèi)型是引用類(lèi)型,那么 copy 的也將是個(gè)引用。
如下面例子,matA 和 matB 地址不一樣,但 matA[0] 和 matB[0] 的地址是一樣的。
func wrongCopyMatrix() {
matA := [][]int{
{0, 1, 1, 0},
{0, 1, 1, 1},
{1, 1, 1, 0},
}
matB := make([][]int, len(matA))
copy(matB, matA)
fmt.Printf("%p, %p\n", matA, matA[0]) // 0xc0000c0000, 0xc0000c2000
fmt.Printf("%p, %p\n", matB, matB[0]) // 0xc0000c0050, 0xc0000c2000
}
如果想 copy 多維切片中的每一個(gè)切片類(lèi)型的元素,那么你需要將每個(gè)切片元素進(jìn)行 初始化 并 拷貝。注意是兩步:先 初始化,再 拷貝。
正確的拷貝一個(gè)多維數(shù)組:
func rightCopyMatrix() {
matA := [][]int{
{0, 1, 1, 0},
{0, 1, 1, 1},
{1, 1, 1, 0},
}
matB := make([][]int, len(matA))
for i := range matA {
matB[i] = make([]int, len(matA[i])) // 注意初始化長(zhǎng)度
copy(matB[i], matA[i])
}
fmt.Printf("%p, %p\n", matA, matA[0]) // 0xc00005c050, 0xc000018560
fmt.Printf("%p, %p\n", matB, matB[0]) // 0xc00005c0a0, 0xc0000185c0
}