Copiar y clonar

Aunque la semántica de movimiento es la opción predeterminada, algunos tipos se copian de forma predeterminada:

fn main() {
    let x = 42;
    let y = x;
    println!("x: {x}");
    println!("y: {y}");
}

Estos tipos implementan el trait Copy.

Puedes habilitar tus propios tipos para que usen la semántica de copia:

#[derive(Copy, Clone, Debug)]
struct Point(i32, i32);

fn main() {
    let p1 = Point(3, 4);
    let p2 = p1;
    println!("p1: {p1:?}");
    println!("p2: {p2:?}");
}
  • Después de la asignación, tanto p1 como p2 tienen sus propios datos.
  • También podemos utilizar p1.clone() para copiar los datos de forma explícita.

Copiar y clonar no es lo mismo:

  • Copiar hace referencia a las copias bit a bit de regiones de memoria y no funciona en cualquier objeto.
  • Copiar no permite lógica personalizada (a diferencia de los constructores de copias de C++).
  • Clonar es una operación más general y que permite un comportamiento personalizado implementando el trait Clone.
  • Copiar no funciona en los tipos que implementan el trait Drop.

En el ejemplo anterior, prueba lo siguiente:

  • Añade un campo String a struct Point. No se compilará porque String no es de tipo Copy.
  • Elimina Copy del atributo derive. El error del compilador se encuentra ahora en println! para p1.
  • Demuestra que funciona si clonas p1.

Si los alumnos preguntan por derive, basta con decir que se trata de una forma de generar código en Rust durante el tiempo de compilación. En este caso, se generan las implementaciones predeterminadas de los traits Copy y Clone.