web-dev-qa-db-fra.com

Pourquoi ne puis-je pas dupliquer une tranche avec `copy ()`?

Je dois faire une copie d'une tranche dans Go. En lisant la documentation, une fonction copie est à ma disposition.

La fonction intégrée de copie permet de copier des éléments d’une tranche source dans une tranche de destination. (Dans un cas particulier, il copiera également des octets d'une chaîne dans une tranche d'octets.) La source et la destination peuvent se chevaucher. Copier renvoie le nombre d'éléments copiés, qui sera le minimum de len (src) et de len (dst).

Mais quand je fais:

arr := []int{1, 2, 3}
tmp := []int{}
copy(tmp, arr)
fmt.Println(tmp)
fmt.Println(arr)

Mon tmp est vide comme avant (j'ai même essayé d'utiliser arr, tmp):

[]
[1 2 3]

Vous pouvez le vérifier en allant terrain de je . Alors, pourquoi ne puis-je pas copier une tranche?

92
Salvador Dali

La fonction intégrée copy(dst, src) copie des éléments min(len(dst), len(src)).

Donc, si votre dst est vide (len(dst) == 0), rien ne sera copié.

Essayez tmp := make([]int, len(arr)) ( Aller au terrain de jeu ):

arr := []int{1, 2, 3}
tmp := make([]int, len(arr))
copy(tmp, arr)
fmt.Println(tmp)
fmt.Println(arr)

Sortie (comme prévu):

[1 2 3]
[1 2 3]

Malheureusement, cela n’est pas documenté dans le package builtin , mais dans le package . Go Spécification de la langue: Ajout à et copier des tranches :

Le nombre d'éléments copiés est au minimum de len(src) et len(dst).

Modifier:

Enfin, la documentation de copy() a été mise à jour et contient maintenant le fait que la longueur minimale de la source et de la destination sera copiée:

Copier renvoie le nombre d'éléments copiés, qui sera le minimum de len (src) et len ​​(dst).

160
icza

Un autre moyen simple de le faire consiste à utiliser append qui allouera la tranche dans le processus.

arr := []int{1, 2, 3}
tmp := append([]int(nil), arr...)  // Notice the ... splat
fmt.Println(tmp)
fmt.Println(arr)

Sortie (comme prévu):

[1 2 3]
[1 2 3]

Donc, un raccourci pour copier tableau arr serait append([]int(nil), arr...)

https://play.golang.org/p/sr_4ofs5GW

17
Dave

Si vos tranches avaient la même taille, cela fonctionnerait :

arr := []int{1, 2, 3}
tmp := []int{0, 0, 0}
i := copy(tmp, arr)
fmt.Println(i)
fmt.Println(tmp)
fmt.Println(arr)

Donnerait:

3
[1 2 3]
[1 2 3]

De " Go Tranches: utilisation et internes ":

La fonction de copie prend en charge la copie entre tranches de longueurs différentes (. Elle ne copie que jusqu’au plus petit nombre d’éléments ).

L'exemple habituel est:

t := make([]byte, len(s), (cap(s)+1)*2)
copy(t, s)
s = t
12
VonC

Copy () fonctionne pour la plus petite longueur de dst et de src, vous devez donc initialiser le dst à la longueur souhaitée.

A := []int{1, 2, 3}
B := make([]int, 3)
copy(B, A)
C := make([]int, 2)
copy(C, A)
fmt.Println(A, B, C)

Sortie:

[1 2 3] [1 2 3] [1 2]

Vous pouvez initialiser et copier tous les éléments d’une ligne en utilisant append () sur une tranche nulle.

x := append([]T{}, []...)

Exemple:

A := []int{1, 2, 3}
B := append([]int{}, A...)
C := append([]int{}, A[:2]...)
fmt.Println(A, B, C)    

Sortie:

[1 2 3] [1 2 3] [1 2]

En comparant avec allocation + copy (), pour plus de 1 000 éléments, utilisez append. En fait, au-dessous de 1 000, la différence peut être négligée, faites-la pour la règle à moins que vous n'ayez beaucoup de tranches.

BenchmarkCopy1-4                50000000            27.0 ns/op
BenchmarkCopy10-4               30000000            53.3 ns/op
BenchmarkCopy100-4              10000000           229 ns/op
BenchmarkCopy1000-4              1000000          1942 ns/op
BenchmarkCopy10000-4              100000         18009 ns/op
BenchmarkCopy100000-4              10000        220113 ns/op
BenchmarkCopy1000000-4              1000       2028157 ns/op
BenchmarkCopy10000000-4              100      15323924 ns/op
BenchmarkCopy100000000-4               1    1200488116 ns/op
BenchmarkAppend1-4              50000000            34.2 ns/op
BenchmarkAppend10-4             20000000            60.0 ns/op
BenchmarkAppend100-4             5000000           240 ns/op
BenchmarkAppend1000-4            1000000          1832 ns/op
BenchmarkAppend10000-4            100000         13378 ns/op
BenchmarkAppend100000-4            10000        142397 ns/op
BenchmarkAppend1000000-4            2000       1053891 ns/op
BenchmarkAppend10000000-4            200       9500541 ns/op
BenchmarkAppend100000000-4            20     176361861 ns/op
10
Esze

Spécification du langage de programmation Go

Ajout et copie de tranches

La fonction copy copie les éléments de tranche d'une source src vers un dst de destination et renvoie le nombre d'éléments copiés. Les deux arguments doivent avoir le même type d'élément T et doivent pouvoir être assignés à une tranche de type [] T. Le nombre d'éléments copiés est le minimum de len (src) et de len (dst). Dans un cas particulier, copy accepte également un argument de destination pouvant être assigné à octet de type [] avec un argument source de type chaîne. Ce formulaire copie les octets de la chaîne dans la tranche d’octets.

copy(dst, src []T) int
copy(dst []byte, src string) int

tmp a besoin de suffisamment de place pour arr. Par exemple,

package main

import "fmt"

func main() {
    arr := []int{1, 2, 3}
    tmp := make([]int, len(arr))
    copy(tmp, arr)
    fmt.Println(tmp)
    fmt.Println(arr)
}

Sortie:

[1 2 3]
[1 2 3]
2
peterSO