Copy Types

While move semantics are the default, certain types are copied by default:

  1. fn main() {
  2.     let x = 42;
  3.     let y = x;
  4.     println!("x: {x}"); // would not be accessible if not Copy
  5.     println!("y: {y}");
  6. }

These types implement the Copy trait.

You can opt-in your own types to use copy semantics:

  1. #[derive(Copy, Clone, Debug)]
  2. struct Point(i32, i32);
  3. fn main() {
  4.     let p1 = Point(3, 4);
  5.     let p2 = p1;
  6.     println!("p1: {p1:?}");
  7.     println!("p2: {p2:?}");
  8. }
  • After the assignment, both p1 and p2 own their own data.
  • We can also use p1.clone() to explicitly copy the data.

This slide should take about 5 minutes.

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 to struct Point. It will not compile because String is not a Copy type.
  • Remove Copy from the derive attribute. The compiler error is now in the println! for p1.
  • Show that it works if you clone p1 instead.

More to Explore

  • Shared references are Copy/Clone, mutable references are not. This is because Rust requires that mutable references be exclusive, so while it’s valid to make a copy of a shared reference, creating a copy of a mutable reference would violate Rust’s borrowing rules.