RustArena

Step 5 of 7

Borrows end at their last use

A borrow doesn't last until the end of the scope. It lasts from where the reference is created to the last place it's used. (The compiler feature is called non-lexical lifetimes; Rust has worked this way since 2018.)

fn main() {
    let mut scores = vec![10, 20, 30];
    let first = &scores[0];
    println!("first: {}", first);    // last use of `first`: the borrow ends here
    scores.push(40);                  // so changing scores is fine
    println!("{:?}", scores);
}
first: 10
[10, 20, 30, 40]
let first = &scores[0];   ─┐  shared borrow of scores starts
println!("{}", first);    ─┘  last use: the borrow ends
scores.push(40);              no borrow active: OK

So many borrow errors are fixed by reordering: finish using the reference before you change, move or reassign the owner. The error messages help: they point at three places, where the borrow starts, the conflicting action, and the "later used here" line that keeps the borrow alive. Move that later use above the conflict, or stop needing it.

Borrows passed to a function last only for the call: after add_points(&mut score, 5); returns, you can use score freely.

Moving while borrowed: E0505

fn main() {
    let name = String::from("Ferris");
    let r = &name;
    let moved = name;
    println!("{} {}", r, moved);
}
error[E0505]: cannot move out of `name` because it is borrowed
 --> src/main.rs:4:17
  |
2 |     let name = String::from("Ferris");
  |         ---- binding `name` declared here
3 |     let r = &name;
  |             ----- borrow of `name` occurs here
4 |     let moved = name;
  |                 ^^^^ move out of `name` occurs here
5 |     println!("{} {}", r, moved);
  |                       - borrow later used here

If name moved (say, into a function that drops it), r would point at a value that no longer exists. Fix: use r before the move, or use moved instead of r afterwards.

Assigning while borrowed: E0506

fn main() {
    let mut score = 10;
    let r = &score;
    score = 20;
    println!("{} {}", r, score);
}
error[E0506]: cannot assign to `score` because it is borrowed
 --> src/main.rs:4:5
  |
3 |     let r = &score;
  |             ------ `score` is borrowed here
4 |     score = 20;
  |     ^^^^^^^^^^ `score` is assigned to here but it was already borrowed
5 |     println!("{} {}", r, score);
  |                       - borrow later used here

A & promises that the value won't change while you're looking at it. Here you want the old number after it changed, so don't borrow it at all: copy it, let old = score;.

Common mistakes

Your task

Fix this program by reordering one line (no .clone(), no new strings) so it prints:

was: Rust for Beginners
now: Rust for Beginners, 2nd edition

Challenge 2

archive takes ownership of the report, but preview still borrows it afterwards (E0505). Fix it by reordering, without .clone(), so it prints:

preview: Q3 sales: up 12%
archived 16 bytes

Challenge 3

This program has three borrow errors: E0506, E0502 and E0505. Fix all three without .clone(). Each needs a different idea: copy a Copy value instead of borrowing it, borrow after changing instead of before, and let a function borrow instead of taking ownership. It should print:

level: 1 -> 2
first item: claw (2 items now)
ferris -> FERRIS

Previous: The rules: many readers or one writer Next: No dangling references