Ownership
Copy Types
A Copy type is a type whose values can be duplicated cleanly and completely by a simple bitwise copy of stack memory (memcpy), without needing to allocate heap memory or duplicate external system resources. When a type implements the Copy marker trait, assigning it to another variable or passing it by value to a function copies the value instead of moving it, leaving the original variable valid and initialized.
Move vs Copy Behavior
For a Copy type such as i32, let y = x; copies the 4 bytes on the stack and leaves both x and y usable:
Stack Layout for `let x: i32 = 42; let y = x;`:
+---------------+
| x: i32 = 42 | <-- Remains valid and initialized!
+---------------+
| y: i32 = 42 | <-- Independent 4-byte bitwise copy
+---------------+
fn print_number(n: i32) {
println!("Inside function: n = {n}");
}
fn main() {
let x: i32 = 42;
let y = x; // Bitwise copy (`i32` implements `Copy`)
print_number(x); // Passes another copy of `x`
// Both `x` and `y` remain completely valid:
println!("After assignment and call: x = {x}, y = {y}");
}
Inside function: n = 42
After assignment and call: x = 42, y = 42
Built-In Types That Implement Copy
| Category | Types That Are Copy |
Why They Are Safe to Copy Bit-for-Bit |
|---|---|---|
| Integers | i8..i128, isize, u8..u128, usize |
Pure stack bit patterns with no heap pointers or destructors |
| Floats | f32, f64 |
Pure 4-byte or 8-byte IEEE 754 bit patterns |
| Booleans & Characters | bool, char, () |
Self-contained 1-byte, 4-byte, or 0-byte stack values |
| Shared References | &T (for any T, even &String or &Vec<T>!) |
Copying a read-only pointer just creates another shared reader |
Raw Pointers & fn Pointers |
*const T, *mut T, fn(A) -> B |
Plain machine addresses with no automatic destructor |
Arrays [T; N] |
[T; N] if and only if T: Copy |
Contiguous block of N copyable elements on the stack |
Tuples (T1, T2, ...) |
(T1, T2, ...) if and only if all elements are Copy |
Contiguous stack fields that are all copyable |
Option<T> / Result<T, E> |
Option<T> / Result<T, E> when T: Copy (and E: Copy) |
Tag + copyable payload on the stack |
fn main() {
let pair: (i32, bool) = (10, true);
let fixed_arr: [u8; 3] = [1, 2, 3];
let text = String::from("shared");
let shared_ref: &String = &text;
// All three assignments below perform implicit bitwise copies:
let pair_copy = pair;
let arr_copy = fixed_arr;
let ref_copy = shared_ref;
println!("Originals still valid: {pair:?}, {fixed_arr:?}, '{shared_ref}'");
println!("Copies: {pair_copy:?}, {arr_copy:?}, '{ref_copy}'");
}
Originals still valid: (10, true), [1, 2, 3], 'shared'
Copies: (10, true), [1, 2, 3], 'shared'
Types That Are NOT Copy
| Type | Why It Cannot Be Copy |
|---|---|
String, Vec<T>, Box<T> |
Owns a heap buffer; bitwise copying the stack header would cause a double free when both copies drop |
std::fs::File, TcpStream |
Owns an OS descriptor that must be closed once |
&mut T (Mutable reference) |
Must remain exclusive; copying &mut T would create two simultaneous mutable aliases to the same data |
[String; 2] or (i32, String) |
Contains at least one non-Copy field (String) |