How to tell whether a type will move or copy
Short answer: ask the compiler. Write fn is_copy<T: Copy>() {} once, call it with the type you’re
wondering about, and read the answer: an error means assignment moves the value, and no error means it
copies. Your own structs are never Copy until you ask for it, even when every field is.
Ask the compiler
Section titled “Ask the compiler”Copy is a marker trait with no methods. It says a value can be duplicated by copying its bytes, and it
does nothing on its own — which makes it a good question to ask. A function bounded on Copy accepts a
type only if that type is Copy:
fn is_copy<T: Copy>() {}
fn main() { is_copy::<i32>(); is_copy::<bool>(); is_copy::<Option<i32>>(); is_copy::<(u8, u8)>();
println!("none of those four lines was an error");}none of those four lines was an errorThe only line of output is the println!. The answers are the silent absence of errors, and that’s the
awkward part of testing this in Rust: there’s no function that returns a bool, because Copy is a
property of the type at compile time. Either the program compiles or the line you added doesn’t. The test
takes any type name, including ones you didn’t write, and generics — Option<i32> is Copy because the
thing inside it is.
When the answer is no
Section titled “When the answer is no”Swap in a type that isn’t Copy and the compiler names it:
fn is_copy<T: Copy>() {}
fn main() { is_copy::<String>();}error[E0277]: the trait bound `String: Copy` is not satisfied --> src/main.rs:4:15 |4 | is_copy::<String>(); | ^^^^^^ the trait `Copy` is not implemented for `String` |note: required by a bound in `is_copy` --> src/main.rs:1:15 |1 | fn is_copy<T: Copy>() {} | ^^^^ required by this bound in `is_copy`
For more information about this error, try `rustc --explain E0277`.The header names the trait and the type, and the caret sits under the type argument you wrote. The note:
points back at is_copy, because that’s where the requirement came from. For a library type you don’t
own, the header is the whole answer.
Your own structs are never Copy
Section titled “Your own structs are never Copy”The part that catches people is that a struct built entirely from Copy fields is still not Copy:
fn is_copy<T: Copy>() {}
struct Point { x: i32, y: i32,}
fn main() { is_copy::<Point>();}error[E0277]: the trait bound `Point: Copy` is not satisfied --> src/main.rs:9:15 |9 | is_copy::<Point>(); | ^^^^^ the trait `Copy` is not implemented for `Point` |note: required by a bound in `is_copy` --> src/main.rs:1:15 |1 | fn is_copy<T: Copy>() {} | ^^^^ required by this bound in `is_copy`help: consider annotating `Point` with `#[derive(Copy)]` |3 + #[derive(Copy)]4 | struct Point { |
For more information about this error, try `rustc --explain E0277`.Point is two i32s and a name, and Rust still moves it. Deriving is opt-in. The help: at the bottom
tells you so, though following it word for word gives you a second error, because a Copy type has to be
Clone too:
#[derive(Copy)]struct Point { x: i32, y: i32,}
fn is_copy<T: Copy>() {}
fn main() { is_copy::<Point>();}error[E0277]: the trait bound `Point: Clone` is not satisfied --> src/main.rs:2:8 |1 | #[derive(Copy)] | ---- in this derive macro expansion2 | struct Point { | ^^^^^ the trait `Clone` is not implemented for `Point` |note: required by a bound in `Copy` --> /rustc/b940084d7eb6a299eb4bfeb8e34901bc051e7ac4/library/core/src/marker.rs:454:0help: consider annotating `Point` with `#[derive(Clone)]` |2 + #[derive(Clone)]3 | struct Point { |
For more information about this error, try `rustc --explain E0277`.So write both:
fn is_copy<T: Copy>() {}
#[derive(Copy, Clone)]struct Point { x: i32, y: i32,}
fn main() { is_copy::<Point>();
let a = Point { x: 1, y: 2 }; let b = a;
println!("a is still usable: {} {}", a.x, a.y); println!("b copies it: {} {}", b.x, b.y);}a is still usable: 1 2b copies it: 1 2That’s everything Copy changes at a call site: let b = a; copies instead of moving, so a is still
usable afterwards.
Two things that block the derive
Section titled “Two things that block the derive”A field that isn’t Copy blocks the whole struct, and the error points at the field:
#[derive(Copy, Clone)]struct Label { text: String,}
fn main() { let label = Label { text: String::from("hi"), };
println!("{}", label.text);}error[E0204]: the trait `Copy` cannot be implemented for this type --> src/main.rs:2:8 |1 | #[derive(Copy, Clone)] | ---- in this derive macro expansion2 | struct Label { | ^^^^^3 | text: String, | ------------ this field does not implement `Copy`
For more information about this error, try `rustc --explain E0204`.A destructor blocks it too, even when every field is Copy:
#[derive(Copy, Clone)]struct Noisy { id: u32,}
impl Drop for Noisy { fn drop(&mut self) { println!("dropping {}", self.id); }}
fn main() { let noisy = Noisy { id: 1 };
println!("{}", noisy.id);}error[E0184]: the trait `Copy` cannot be implemented for this type; the type has a destructor --> src/main.rs:2:8 |1 | #[derive(Copy, Clone)] | ---- in this derive macro expansion2 | struct Noisy { | ^^^^^ `Copy` not allowed on types with destructors |note: destructor declared here --> src/main.rs:7:5 |7 | fn drop(&mut self) { | ^^^^^^^^^^^^^^^^^^
For more information about this error, try `rustc --explain E0184`.Drop and Copy never coexist, because a copied value would be cleaned up twice. Either error leaves you
with a type that moves, which is fine — most types are supposed to. If you’re not sure which field is at
fault, run the test from the top of this page on the field’s type on its own. It’s the same one function,
and it names the type that fails.
Related
Section titled “Related”- Why does Rust move values instead of copying them? — where
Copyfirst shows up - What happens to the original variable after a move? — this page’s predecessor
- How to fix error E0382: borrow of moved value — what you get when a type doesn’t copy
- Moves and ownership — the rest of this chapter
- Next in this chapter: how move semantics work in Rust