Ownership

Common Ownership Compiler Errors

When a program violates one of Rust's ownership rules, rustc rejects the code at compile time with a specific E0xxx error code and suggests how to fix it.

Quick Reference of Ownership Error Codes

Error Code Diagnostic Headline Root Cause Standard Fix
E0382 borrow / use of moved value Using a non-Copy variable after moving its ownership elsewhere Pass a reference (&x), clone explicitly (x.clone()), or reorder usages
E0507 cannot move out of ... which is behind a shared/mutable reference Trying to move a non-Copy value (String) out of *r, &struct.field, or &vec[i] Borrow the field (&r.field), .clone() it, or use std::mem::take on &mut
E0508 cannot move out of type '[T; N]', a non-copy array Indexing let elem = arr[i]; by value on an array of non-Copy items Borrow &arr[i], use std::mem::take(&mut arr[i]), or destructure let [a, b] = arr;
E0509 cannot move out of type 'T', which implements the 'Drop' trait Moving a single field out of a struct that has a custom impl Drop Borrow &s.field, .clone() the field, or wrap the field in Option<Field> and call .take()
E0040 explicit use of destructor method Calling x.drop() directly instead of drop(x) Call drop(x) (std::mem::drop(x))

1. Use of Moved Value Inside a Loop (E0382)

A frequent way to trigger E0382 is moving an outer non-Copy variable inside a loop body. Even if the variable is initialized before the loop starts, the first iteration moves it, leaving it uninitialized on the second iteration:

// ❌ does not compile
fn consume(s: String) {
    println!("{s}");
}

fn main() {
    let prefix = String::from("item");

    for i in 0..3 {
        consume(prefix); // Moved on iteration 0; uninitialized on iteration 1!
        println!("{i}");
    }
}
error[E0382]: use of moved value: `prefix`
 --> src/main.rs:9:17
  |
6 |     let prefix = String::from("item");
  |         ------ move occurs because `prefix` has type `String`, which does not implement the `Copy` trait
7 |
8 |     for i in 0..3 {
  |     ------------- inside of this loop
9 |         consume(prefix);
  |                 ^^^^^^ value moved here, in previous iteration of loop

error: aborting due to 1 previous error

Fix: Change consume to borrow s: &str (consume(&prefix)), or pass consume(prefix.clone()) if each iteration genuinely requires an independent owned String.

2. Moving Out of an Indexed Vec<T> or Slice (E0507)

Because indexing a vector (vec[i]) actually calls Index::index(&vec, i) -> &T and dereferences the returned reference (*vec.index(i)), writing let item = vec[0]; on a Vec<String> attempts to move out of a reference and fails with E0507:

// ❌ does not compile
fn main() {
    let list = vec![String::from("alpha"), String::from("beta")];
    let first: String = list[0];
}
error[E0507]: cannot move out of index of `Vec<String>`
 --> src/main.rs:3:25
  |
3 |     let first: String = list[0];
  |                         ^^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait
  |
help: consider borrowing here
  |
3 |     let first: &String = &list[0];
  |                          +

error: aborting due to 1 previous error

Fixes when you need an owned String from Vec<String>:

fn main() {
    let mut list = vec![
        String::from("alpha"),
        String::from("beta"),
        String::from("gamma"),
    ];

    // 1. Borrow without moving (`&String`):
    let borrowed: &String = &list[0];
    println!("Borrowed: '{borrowed}'");

    // 2. Remove and take ownership in O(1) by swapping with the last element:
    let owned_first: String = list.swap_remove(0);
    println!("Extracted via swap_remove(0): '{owned_first}', remaining: {list:?}");
}
Borrowed: 'alpha'
Extracted via swap_remove(0): 'alpha', remaining: ["gamma", "beta"]