In Rust, some simple types are “implicitly copyable” and when you assign them or pass them as arguments, the receiver will get a copy, leaving the original value in place. Copy types are like “value” types in Java or JS language. Therefore Copy can be used to avoid borrow, lifetime annotation or smart pointer.
Native types implement Copy
// u8 implements Copy
let x: u8 = 123;
let y = x; // copy happen implicitly
println!("x={}, y={}", x, y); // x can still be used
// Vec<u8> implements Clone, but not Copy
let v: Vec<u8> = vec![1, 2, 3];
let w = v; // This would *move* the value, rendering v unusable.
Copy simply tells the compiler that this previous copy is still valid and can be reused. The compiler understands that it doesn't need to consider move. Reassignments or passing-by-values leave behind a bitwise copy of the object at its previous position. Values are safely duplicated via memcpy. This implies the value is somehow primitive or cheap to copy. It is guaranteed to have zero overhead.
Reassignment
#[derive(Debug, Clone, Copy)]
pub struct PointCloneAndCopy {
pub x: f64,
}
#[derive(Debug, Clone)]
pub struct PointCloneOnly {
pub x: f64,
}
fn test_copy_and_clone() {
let p1 = PointCloneAndCopy { x: 0. };
let p2 = p1; // Copied automatically
println!("{:?} {:?}", p1, p2);
}
fn test_clone_only() {
let p1 = PointCloneOnly { x: 0. };
let p2 = p1; // This is a move instead
println!("{:?} {:?}", p1, p2); // ERROR!
}
Every Copy type is also required to be Clone. Clone is a supertrait of Copy, so everything which is Copy must also implement Clone. If a type is Copy then its Clone implementation only needs to return *self.
Passing-by-value
Consider this enum TokenType which doesn’t implement Copy. When we pass it as an argument to a method, we do it as borrow using &.
// No Copy
#[derive(Clone, Debug)]
enum TokenType {
Plus,
Minus,
// ...
}
fn check(&self, token_type: &TokenType) -> bool {
// ...
}
// This is *borrow* i.e. pass-by-reference
self.check(&TokenType.Plus)
I was bothered by the added & everywhere. I understand that the borrow is idiomatic in Rust, but here it feels a bit verbose, especially for enum comparisons where we're not mutating or consuming the value — just checking it. So I made TokenType implement Copy.
#[derive(Copy, Clone, Debug)]
enum TokenType {
Plus,
Minus,
// ...
}
// Now its clean pass-by-value
self.check(TokenType.PLUS)
Conclusion
Copy is meant to be implemented for "cheap" types, such as u8 or simple Enums, as in the example above. If you write a quite heavyweight type, for which you think a move is more efficient than a copy, make it not implement Copy. Note that in the u8 case, we cannot possibly be more efficient with a move, since under the hood it would probably at least entail a pointer copy - which is already as expensive as a u8 copy, so why bother.