Ownership

Ownership in Tuples and Arrays

Tuples (T1, T2, ...) and fixed-size arrays [T; N] own all of their elements directly inline on the stack. How ownership behaves when you index, destructure, or assign a tuple or array depends on whether its element types implement Copy.

Tuples: Element-By-Element Ownership vs Array Indexing

There is a fundamental difference between accessing a tuple field (tuple.0) and indexing an array element (array[i]):

Operation Allowed on Non-Copy Elements (e.g., String)? Why
Tuple field move (let s = tup.0;) Yes! (Performs a partial move of .0 only) .0 is a compile-time constant field, so rustc tracks which exact fields of tup have been moved
Array index move (let s = arr[i];) No! (E0508: cannot move out of type '[String; N]') i can be an arbitrary runtime usize; the compiler cannot track which array slots are uninitialized at runtime!
Array pattern destructuring (let [a, b] = arr;) Yes! Moves all elements out of arr simultaneously in a single pattern
fn main() {
    // 1. Moving a single non-Copy element out of a tuple is ALLOWED (partial move):
    let tup: (String, i32) = (String::from("moved from tuple"), 42);
    let extracted_str = tup.0;
    let remaining_int = tup.1; // `tup.1` is still valid!
    println!("From tuple: '{extracted_str}' and {remaining_int}");

    // 2. Moving all elements out of a non-Copy array via destructuring is ALLOWED:
    let arr: [String; 2] = [String::from("first"), String::from("second")];
    let [first, second] = arr;
    println!("From array destructuring: '{first}' and '{second}'");
}
From tuple: 'moved from tuple' and 42
From array destructuring: 'first' and 'second'

Why Moving Out of an Array by Index [i] Fails (E0508)

Attempting to move a String out of an array using arr[0] fails at compile time because it would leave arr[0] uninitialized while arr[1] is still alive (and when arr goes out of scope, Drop expects every element of [T; N] to be initialized):

// ❌ does not compile
fn main() {
    let names = [String::from("Alice"), String::from("Bob")];
    let first = names[0];
}
error[E0508]: cannot move out of type `[String; 2]`, a non-copy array
 --> src/main.rs:3:17
  |
3 |     let first = names[0];
  |                 ^^^^^^^^
  |                 |
  |                 cannot move out of here
  |                 move occurs because `names[_]` has type `String`, which does not implement the `Copy` trait
  |
help: consider borrowing here
  |
3 |     let first = &names[0];
  |                 +

error: aborting due to 1 previous error

Extracting One Element from a Non-Copy Array Safely

To extract a single element from [String; N] without cloning:

  1. Borrow it: let first: &String = &names[0];
  2. Swap/take it from a mut array: let first: String = std::mem::take(&mut names[0]); (leaves an empty String::new() in names[0]).
  3. Destructure with ..: let [first, ..] = names; (moves first and drops the remaining elements).