Esse problema parece sugerir que é apenas um detalhe da implementação ( memcpyvs ???), mas não consigo encontrar nenhuma descrição explícita das diferenças.
Esse problema parece sugerir que é apenas um detalhe da implementação ( memcpyvs ???), mas não consigo encontrar nenhuma descrição explícita das diferenças.
Respostas:
Clonefoi projetado para duplicações arbitrárias: uma Cloneimplementação para um tipo Tpode executar operações arbitrariamente complicadas, necessárias para criar um novoT . É uma característica normal (além de estar no prelúdio) e, portanto, exige ser usada como uma característica normal, com chamadas de método etc.
A Copycaracterística representa valores que podem ser duplicados com segurança via memcpy: coisas como reatribuições e passar um argumento por valor para uma função são sempre memcpys, e, para os Copytipos, o compilador entende que não precisa considerar essas mudanças .
Cloneé uma cópia em profundidade e é uma cópia em Copysombra?
Cloneabre a possibilidade de que o tipo possa fazer uma cópia profunda ou superficial: "arbitrariamente complicado".
A principal diferença é que a clonagem é explícita. Notação implícita significa mover para um não- Copytipo.
// 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.
A propósito, todo Copytipo também é necessário Clone. No entanto, eles não são obrigados a fazer a mesma coisa! Para seus próprios tipos, .clone()pode ser um método arbitrário de sua escolha, enquanto a cópia implícita sempre acionará uma memcpy, não a clone(&self)implementação.
yser movido x, e não uma cópia, como no seu último exemplo comentado w = v. Como você especificaria isso?
Copydeve ser implementado para tipos "baratos", como u8no exemplo. Se você escreve um tipo bastante pesado, para o qual considera que uma movimentação é mais eficiente que uma cópia, não implemente Copy. Observe que, no caso do u8, você não pode ser mais eficiente com um movimento, pois, por baixo do capô, isso provavelmente implicaria pelo menos uma cópia indicadora - que já é tão cara quanto uma cópia do u8, então, por que se preocupar?
Copycaracterística afeta os escopos implícitos da vida útil das variáveis? Se sim, acho isso digno de nota.
Como já coberto por outras respostas:
Copy é implícito, barato e não pode ser reimplementado (memcpy).Clone é explícito, pode ser caro e pode ser reimplementado arbitrariamente.O que às vezes falta na discussão de Copyvs Cloneé que ele também afeta como o compilador usa movimentos versus cópias automáticas. Por exemplo:
#[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);
}
O primeiro exemplo ( PointCloneAndCopy) funciona bem aqui por causa da cópia implícita, mas o segundo exemplo ( PointCloneOnly) com erro após o uso após a movimentação:
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 a mudança implícita, poderíamos ligar explicitamente let p2 = p1.clone();.
Isso pode levantar a questão de como forçar uma movimentação de um tipo que implementa a característica de cópia? . Resposta curta: você não pode / não faz sentido.