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);
   ```

4. ```
   fn main() {
   ```
5. ```
       let p1 = Point(3, 4);
   ```
6. ```
       let p2 = p1;
   ```
7. ```
       println!("p1: {p1:?}");
   ```
8. ```
       println!("p2: {p2:?}");
   ```
9. ```
   }
   ```
  • 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.