Move Semantics & Copy
Assignment and passing by value either move (transfer ownership) or copy (duplicate bits) depending on the type. Clone provides explicit duplication when needed.
Search across all documentation pages
Assignment and passing by value either move (transfer ownership) or copy (duplicate bits) depending on the type. Clone provides explicit duplication when needed.
#[derive(Clone, Debug)]
struct Config { host: String, port: u16 }
fn main() {
let port: u16 = 8080; // Copy
let p2 = port;
let cfg = Config { host: "localhost".into(), port };
let cfg2 = cfg.clone(); // explicit deep copy
println!("{port} {:?} {:?}", cfg, cfg2);
}When to reach for this: Deciding whether a type should be Copy, when to clone(), and designing APIs that move vs borrow.
#[derive(Copy, Clone, Debug)]
struct Point { x: i32, y: i32 }
fn translate(p: Point, dx: i32) -> Point {
Point { x: p.x + dx, y: p.y }
}
fn main() {
let origin = Point { x: 0, y: 0 };
let moved = origin; // Copy - both valid
let shifted = translate(moved, 5);
println!("{origin:?} {shifted:?}");
}What this demonstrates:
Point is Copy because all fields are Copyorigin remains usable after assignmentCopy candidatesString cannot be Copy (heap ownership)Copy assignment invalidates the source bindingVec, String, HashMap always move on assignmentCopy Requirements// All fields Copy, no Drop impl (usually)
#[derive(Copy, Clone)]
struct Flags(u32);Types with custom Drop generally cannot be Copy.
Clone vs Copy| Trait | When | Effect |
|---|---|---|
Copy | Implicit on assignment | Bitwise duplicate |
Clone | Explicit .clone() | User-defined duplication |
Clone on Collectionslet v1 = vec![1, 2];
let v2 = v1.clone(); // clones elements if T: CloneCopy on struct with String - Compile error. Fix: Remove Copy or use &str/Arc<str> if sharing needed.Vec - It moves. Fix: .clone() explicitly when duplicate needed.Copy + Drop conflict - Custom drop means move semantics matter. Fix: Do not implement Copy.
| Alternative | Use When | Don't Use When |
|---|---|---|
Borrow &T | Read-only shared access | Caller must retain ownership for return |
Rc/Arc | Shared ownership without deep clone | Single owner is clearer |
Cow<'a, T> | Sometimes borrow, sometimes own | Always one mode |
| Move only | Transfer is intended | Callers need to keep using value |
For Copy types, yes. For heap types, move copies the stack metadata (pointer, len, cap), not heap data.
Yes with unsafe impl Copy, but derive is standard. All fields must already be Copy.
Clone semantics are type-defined. Arc::clone only increments refcount.
i32 is entirely on stack with no ownership. String owns heap allocation.
[T; N] is Copy when T: Copy. Large arrays are Copy but expensive to bitwise copy.
Use MaybeUninit in unsafe patterns. Safe code uses fully initialized values.
Yes for non-Copy types. Optimizer may elide copies in practice (NRVO).
Yes if all variants' payloads are Copy.
Derive recurses fields. Heap fields clone their contents.
Owned data moves into futures. Send bounds govern cross-thread moves.
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.
Reviewed by Chris St. John·Last updated Jul 19, 2026