What is the difference between Copy and Clone?
The main difference is that cloning is explicit. Implicit notation means move for a 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.
By the way, every Copy
type is also required to be Clone
. However, they are not required to do the same thing! For your own types, .clone()
can be an arbitrary method of your choice, whereas implicit copying will always trigger a memcpy
, not the clone(&self)
implementation.
Clone
is designed for arbitrary duplications: a Clone
implementation for a type T
can do arbitrarily complicated operations required to create a new T
. It is a normal trait (other than being in the prelude), and so requires being used like a normal trait, with method calls, etc.
The Copy
trait represents values that can be safely duplicated via memcpy
: things like reassignments and passing an argument by-value to a function are always memcpy
s, and so for Copy
types, the compiler understands that it doesn't need to consider those a move.
As already covered by other answers:
Copy
is implicit, inexpensive, and cannot be re-implemented (memcpy).Clone
is explicit, may be expensive, and may be re-implement arbitrarily.
What is sometimes missing in the discussion of Copy
vs Clone
is that it also affects how the compiler uses moves vs automatic copies. For instance:
#[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);
}
(Rust Playground)
The first example (PointCloneAndCopy
) works fine here because of the implicit copy, but the second example (PointCloneOnly
) would error with a use after move:
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
To avoid the implicit move, we could explicitly call let p2 = p1.clone();
.
This may raise the question of how to force a move of a type which implements the Copy trait?.
Short answer: You can't / doesn't make sense.