Ce problème semble impliquer qu'il ne s'agit que d'un détail d'implémentation ( memcpy
vs ???), mais je ne trouve aucune description explicite des différences.
Ce problème semble impliquer qu'il ne s'agit que d'un détail d'implémentation ( memcpy
vs ???), mais je ne trouve aucune description explicite des différences.
Réponses:
Clone
est conçu pour les duplications arbitraires: une Clone
implémentation d'un type T
peut effectuer des opérations arbitrairement compliquées nécessaires pour créer un nouveau T
. C'est un trait normal (autre que d'être dans le prélude), et nécessite donc d'être utilisé comme un trait normal, avec des appels de méthode, etc.
Le Copy
trait représente des valeurs qui peuvent être dupliquées en toute sécurité via memcpy
: des choses comme les réaffectations et le passage d'un argument par valeur à une fonction sont toujours memcpy
s, et donc pour les Copy
types, le compilateur comprend qu'il n'a pas besoin de les considérer comme un mouvement .
Clone
une copie profonde et une copie Copy
miroir?
Clone
ouvre la possibilité que le type puisse faire une copie profonde ou superficielle: "arbitrairement compliqué".
La principale différence est que le clonage est explicite. La notation implicite signifie déplacer pour un non- Copy
type.
// u8 implements Copy
let x: u8 = 123;
let y = x;
// x can still be used
println!("x={}, y={}", x, y);
// Vec<u8> implements Clone, but not Copy
let v: Vec<u8> = vec![1, 2, 3];
let w = v.clone();
//let w = v // This would *move* the value, rendering v unusable.
À propos, chaque Copy
type doit également l'être Clone
. Cependant, ils ne sont pas obligés de faire la même chose! Pour vos propres types, cela .clone()
peut être une méthode arbitraire de votre choix, alors que la copie implicite déclenchera toujours a memcpy
, pas l' clone(&self)
implémentation.
y
obtenir un déplacement x
, pas une copie, comme avec votre dernier exemple commenté w = v
. Comment le préciseriez-vous?
Copy
est destiné à être implémenté pour des types "bon marché", comme u8
dans l'exemple. Si vous écrivez un type assez lourd, pour lequel vous pensez qu'un mouvement est plus efficace qu'une copie, ne le faites pas impliquer Copy
. Notez que dans le cas u8, vous ne pouvez pas être plus efficace avec un mouvement, car sous le capot, cela impliquerait probablement au moins une copie de pointeur - qui est déjà aussi chère qu'une copie u8, alors pourquoi s'embêter.
Copy
trait a un impact sur les portées implicites de durée de vie des variables? Si c'est le cas, je pense que c'est remarquable.
Comme déjà couvert par d'autres réponses:
Copy
est implicite, peu coûteux et ne peut pas être réimplémenté (memcpy).Clone
est explicite, peut être coûteux et peut être réimplémenté arbitrairement.Ce qui manque parfois dans la discussion de Copy
vs, Clone
c'est que cela affecte également la façon dont le compilateur utilise les déplacements par rapport aux copies automatiques. Par exemple:
#[derive(Debug, Clone, Copy)]
pub struct PointCloneAndCopy {
pub x: f64,
}
#[derive(Debug, Clone)]
pub struct PointCloneOnly {
pub x: f64,
}
fn test_copy_and_clone() {
let p1 = PointCloneAndCopy { x: 0. };
let p2 = p1; // because type has `Copy`, it gets copied automatically.
println!("{:?} {:?}", p1, p2);
}
fn test_clone_only() {
let p1 = PointCloneOnly { x: 0. };
let p2 = p1; // because type has no `Copy`, this is a move instead.
println!("{:?} {:?}", p1, p2);
}
Le premier exemple ( PointCloneAndCopy
) fonctionne bien ici à cause de la copie implicite, mais le deuxième exemple ( PointCloneOnly
) ferait une erreur avec une utilisation après le déplacement:
error[E0382]: borrow of moved value: `p1`
--> src/lib.rs:20:27
|
18 | let p1 = PointCloneOnly { x: 0. };
| -- move occurs because `p1` has type `PointCloneOnly`, which does not implement the `Copy` trait
19 | let p2 = p1;
| -- value moved here
20 | println!("{:?} {:?}", p1, p2);
| ^^ value borrowed here after move
Pour éviter le déplacement implicite, nous pourrions appeler explicitement let p2 = p1.clone();
.
Cela peut soulever la question de savoir comment forcer un mouvement d'un type qui implémente le trait Copy? . Réponse courte: Vous ne pouvez pas / n'a pas de sens.