Skip to content

Q021. When can a type implement Copy?

Short Answer

A type can implement Copy only when all data it contains is also Copy and the type does not implement Drop. Every field of a struct and every payload of an enum must satisfy that requirement. Eligibility is not automatic: the type author chooses whether implicit duplication is appropriate and stable as part of the public API.

Deep Dive

Common Copy types include numeric primitives, bool, char, shared references, raw pointers, and function pointers. Composite types are eligible only when their contents are Copy:

  • [T; N] is Copy when T: Copy;
  • tuples are Copy when every element is Copy;
  • Option<T> is Copy when T: Copy;
  • a user-defined struct or enum must explicitly implement or derive Copy.

String, Vec<T>, Box<T>, Rc<T>, Arc<T>, and owning OS handles are not Copy. Mutable references are also not Copy, because implicit duplication would violate their exclusive-access contract.

Even an eligible type may intentionally remain non-Copy to preserve unique capability semantics, avoid accidental large copies, or retain the option to add non-Copy fields later. Adding or removing Copy can affect downstream code and is an API design decision.

Internal Model

The compiler verifies structural eligibility. #[derive(Copy)] also derives bounds for generic parameters based on the generated implementation, often requiring T: Copy when a field contains T.

Copy has Clone as a supertrait, so a type must implement both. The usual declaration is #[derive(Clone, Copy)]; writing a manual implementation cannot bypass non-Copy fields or a Drop implementation.

Example

rust
#[derive(Clone, Copy)]
struct UserId(u64);

fn require_copy<T: Copy>(_: T) {}

fn main() {
    let first = UserId(42);
    let second = first;

    require_copy(first);
    println!("{} {}", first.0, second.0);

    // String does not satisfy the Copy bound:
    // require_copy(String::from("Alice"));
}

Common Mistakes

  • Assuming a struct automatically becomes Copy when all fields are Copy.
  • Thinking only primitive types can implement Copy.
  • Treating Copy purely as a performance annotation rather than an API semantic promise.

Follow-ups

  • Why is implementing Copy a public API commitment?
  • How does deriving Copy affect generic bounds?
  • Why is &mut T non-Copy even when T: Copy?

References

  • The Rust Programming Language
  • Rust Reference
  • Rust API Guidelines