Copying and Cloning
While move semantics are the default, certain types are copied by default:
fn main() {
let x = 42;
let y = x;
println!("x: {x}");
println!("y: {y}");
}
These types implement the Copy
trait.
You can opt-in your own types to use copy semantics:
#[derive(Copy, Clone, Debug)]
struct Point(i32, i32);
fn main() {
let p1 = Point(3, 4);
let p2 = p1;
println!("p1: {p1:?}");
println!("p2: {p2:?}");
}
- After the assignment, both
p1
andp2
own their own data. - We can also use
p1.clone()
to explicitly copy the data.
Copying and cloning are not the same thing:
- Copying refers to bitwise copies of memory regions and does not work on arbitrary objects.
- Copying does not allow for custom logic (unlike copy constructors in C++).
- Cloning is a more general operation and also allows for custom behavior by implementing the
Clone
trait. - Copying does not work on types that implement the
Drop
trait.
In the above example, try the following:
- Add a
String
field tostruct Point
. It will not compile becauseString
is not aCopy
type. - Remove
Copy
from thederive
attribute. The compiler error is now in theprintln!
forp1
. - Show that it works if you clone
p1
instead.
If students ask about derive
, it is sufficient to say that this is a way to generate code in Rust at compile time. In this case the default implementations of Copy
and Clone
traits are generated.