Skip to content

Ownership & Moves

Every Rust value has exactly one owner. When you assign a value to another variable, or pass it into a function, what happens depends on whether the type implements Copy.

Types that own heap memory — like String, Vec<i32>, or Box<i32> — do not implement Copy. When you assign one to another variable, the value is moved: the original binding becomes invalid.

fn main() {
let s1 = String::from("hello");
let s2 = s1; // s1 is moved into s2
// println!("{}", s1); // ERROR: s1 was moved
println!("{}", s2); // fine
}

The same rule applies when you pass a value into a function:

fn consume(s: String) {
println!("{}", s);
} // s is dropped here
fn main() {
let name = String::from("Rust");
consume(name); // name is moved
// name is no longer valid here
}

Simple scalar types stored entirely on the stack — integers, bool, char, floating-point numbers, and tuples of these — implement Copy. Assigning or passing them makes a bitwise copy; the original remains valid.

fn main() {
let x: i32 = 42;
let y = x; // x is COPIED, not moved
println!("x={} y={}", x, y); // both valid
}

Common Copy types: i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64, bool, char.

When you need a full independent copy of a heap-owning value, call .clone(). This is an explicit opt-in to a potentially expensive operation.

fn main() {
let original = String::from("keep me");
let copy = original.clone(); // deep copy
println!("original={} copy={}", original, copy);
}

A function can give ownership back to the caller by returning the value:

fn take_and_give_back(s: String) -> String {
s // ownership moves out of the function
}
fn main() {
let s1 = String::from("hello");
let s2 = take_and_give_back(s1);
println!("{}", s2);
}

This is valid but verbose. In practice, you will almost always prefer borrowing (the next lesson) over moving-and-returning.

fn take_ownership(s: String) -> String {
println!("inside take_ownership: {}", s);
s // return ownership to caller
}
fn main() {
// String is NOT Copy — it moves
let s1 = String::from("hello");
let s2 = take_ownership(s1); // s1 is moved
println!("s2 now owns: {}", s2);
// i32 IS Copy — it is copied
let x = 42;
let y = x;
println!("x={} y={}", x, y);
// .clone() makes an explicit deep copy
let original = String::from("keep me");
let cloned = original.clone();
println!("original={} cloned={}", original, cloned);
}
What happens when you assign a String to a new variable in Rust?
Which of these types implements Copy?
How do you get an explicit independent copy of a String?
After passing a String into a function that takes ownership, can the caller use it again?