No olvides que en la informática un error puede tener diferentes soluciones, no obstante mostramos lo más óptimo y eficiente.
Solución:
Clone
está diseñado para duplicaciones arbitrarias: un Clone
implementación para un tipo T
puede hacer operaciones arbitrariamente complicadas requeridas para crear un nuevo T
. Es un rasgo normal (aparte de estar en el preludio), por lo que requiere ser usado como un rasgo normal, con llamadas a métodos, etc.
los Copy
El rasgo representa valores que se pueden duplicar de forma segura a través de memcpy
: cosas como reasignaciones y pasar un argumento por valor a una función siempre son memcpy
s, y así para Copy
tipos, el compilador entiende que no necesita considerarlos como un movimiento.
La principal diferencia es que la clonación es explícita. La notación implícita significa mover para un no-Copy
escribe.
// u8 implements Copy
let x: u8 = 123;
let y = x;
// x can still be used
println!("x=, y=", x, y);
// Vec implements Clone, but not Copy
let v: Vec = vec![1, 2, 3];
let w = v.clone();
//let w = v // This would *move* the value, rendering v unusable.
Por cierto, cada Copy
También se requiere que el tipo sea Clone
. Sin embargo, ¡no están obligados a hacer lo mismo! Para sus propios tipos, .clone()
puede ser un método arbitrario de su elección, mientras que la copia implícita siempre activará un memcpy
no la clone(&self)
implementación.
Como ya está cubierto por otras respuestas:
Copy
es implícito, económico y no se puede volver a implementar (memcpy).Clone
es explícito, puede ser costoso y puede volver a implementarse arbitrariamente.
Lo que a veces falta en la discusión de Copy
contra Clone
es que también afecta cómo el compilador usa movimientos frente a copias automáticas. Por ejemplo:
#[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);
El primer ejemplo (PointCloneAndCopy
) funciona bien aquí debido a la copia implícita, pero el segundo ejemplo (PointCloneOnly
) cometería un error con un uso después del movimiento:
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
Para evitar el movimiento implícito, podríamos llamar explícitamente let p2 = p1.clone();
.
Esto puede plantear la pregunta de cómo forzar un movimiento de un tipo que implementa el rasgo Copiar. Respuesta corta: no puedes/no tiene sentido.
Comentarios y valoraciones del tutorial
Acuérdate de que tienes autorización de agregar una reseña si te ayudó.