Guide contents

Lesson 28 of 94

Fixing Borrow Checker Errors

This lesson is a reference you will come back to. Each section is one error, shown the way you'll meet it in real code, not in a toy example. For each one:

  1. Symptom: code that looks reasonable and the compiler's actual error.
  2. Why: what the compiler is protecting you from.
  3. Fix: the idiomatic repair, which compiles and runs.

The fixes follow a short list of strategies. Once you know them, most borrow errors take seconds to fix:

  • Borrow instead of moving: &x instead of x, &str instead of String, &[T] instead of Vec<T>.
  • Shorten a borrow: use the reference earlier, or copy/clone the small value you need out of it.
  • Reorder: do the mutation before or after the borrow, not during it.
  • Split the borrow: borrow individual fields instead of the whole struct.
  • Use indexes instead of long-lived references into collections.
  • Collect, then apply: gather changes first, apply them after the loop.
  • Move values out of &mut with std::mem::take, replace, or Option::take.
  • Own the data when a reference would have to outlive its source.

1. "use of moved value" after passing a field to a function (E0382)

Symptom. A function takes a String, so calling it moves the field out of the struct.

Rust✗ does not compile · E0382
struct User {
    name: String,
    email: String,
}

fn send_welcome(email: String) {
    println!("welcome mail sent to {email}");
}

fn main() {
    let user = User { name: String::from("Ada"), email: String::from("ada@example.com") };
    send_welcome(user.email);
    println!("{} <{}>", user.name, user.email);
}
Output
error[E0382]: borrow of moved value: `user.email`
  --> src/main.rs:13:36
   |
12 |     send_welcome(user.email);
   |                  ---------- value moved here
13 |     println!("{} <{}>", user.name, user.email);
   |                                    ^^^^^^^^^^ value borrowed here after move
   |
   = note: move occurs because `user.email` has type `String`, which does not implement the `Copy` trait

Why. send_welcome takes ownership, and the email is freed when it returns.

Fix. A function that only reads text should take &str.

Rust
struct User {
    name: String,
    email: String,
}

fn send_welcome(email: &str) {
    println!("welcome mail sent to {email}");
}

fn main() {
    let user = User { name: String::from("Ada"), email: String::from("ada@example.com") };
    send_welcome(&user.email);
    println!("{} <{}>", user.name, user.email);
}
Output
welcome mail sent to ada@example.com
Ada <ada@example.com>

2. "borrow of moved value" after looping over a field (E0382)

Symptom. for item in order.items consumes the vector, so the order is partially moved.

Rust✗ does not compile · E0382
struct Order {
    id: u32,
    items: Vec<String>,
}

fn main() {
    let order = Order { id: 7, items: vec![String::from("lamp"), String::from("bulb")] };
    for item in order.items {
        println!("packing {item}");
    }
    println!("order {} has {} items", order.id, order.items.len());
}
Output
error[E0382]: borrow of moved value: `order.items`
  --> src/main.rs:11:49
   |
 8 |     for item in order.items {
   |                 ----------- `order.items` moved due to this implicit call to `.into_iter()`
...
11 |     println!("order {} has {} items", order.id, order.items.len());
   |                                                 ^^^^^^^^^^^ value borrowed here after move
   |
note: `into_iter` takes ownership of the receiver `self`, which moves `order.items`
  --> /rustc/<version>/library/core/src/iter/traits/collect.rs:310:17
   = note: move occurs because `order.items` has type `Vec<String>`, which does not implement the `Copy` trait
help: consider iterating over a slice of the `Vec<String>`'s content to avoid moving into the `for` loop
   |
 8 |     for item in &order.items {
   |                 +

Fix. Loop over a reference.

Rust
struct Order {
    id: u32,
    items: Vec<String>,
}

fn main() {
    let order = Order { id: 7, items: vec![String::from("lamp"), String::from("bulb")] };
    for item in &order.items {
        println!("packing {item}");
    }
    println!("order {} has {} items", order.id, order.items.len());
}
Output
packing lamp
packing bulb
order 7 has 2 items

3. "cannot borrow as mutable more than once" with two elements (E0499)

Symptom. Two &mut references into the same vector at once.

Rust✗ does not compile · E0499
#[derive(Debug)]
struct Player {
    name: &'static str,
    gold: u32,
}

fn main() {
    let mut players = vec![Player { name: "ana", gold: 50 }, Player { name: "ben", gold: 10 }];
    let giver = &mut players[0];
    let receiver = &mut players[1];
    giver.gold -= 20;
    receiver.gold += 20;
    println!("{:?}", players);
}
Output
error[E0499]: cannot borrow `players` as mutable more than once at a time
  --> src/main.rs:10:25
   |
 9 |     let giver = &mut players[0];
   |                      ------- first mutable borrow occurs here
10 |     let receiver = &mut players[1];
   |                         ^^^^^^^ second mutable borrow occurs here
11 |     giver.gold -= 20;
   |     ---------------- first borrow later used here
   |
   = help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices

Why. The compiler can't prove that indexes 0 and 1 are different at compile time, and two &mut to the same element would break the aliasing rule.

Fix. get_disjoint_mut checks at runtime that the indexes differ and returns both references. Alternatives are split_at_mut, or modifying one element at a time through the index.

Rust
#[derive(Debug)]
struct Player {
    name: &'static str,
    gold: u32,
}

fn main() {
    let mut players = vec![Player { name: "ana", gold: 50 }, Player { name: "ben", gold: 10 }];
    if let Ok([giver, receiver]) = players.get_disjoint_mut([0, 1]) {
        giver.gold -= 20;
        receiver.gold += 20;
    }
    println!("{:?}", players);
}
Output
[Player { name: "ana", gold: 30 }, Player { name: "ben", gold: 30 }]

4. "cannot borrow as mutable because it is also borrowed as immutable" while caching a reference (E0502)

Symptom. Keeping a reference to an element, then changing the vector.

Rust✗ does not compile · E0502
fn main() {
    let mut queue = vec![String::from("job-1"), String::from("job-2")];
    let current = &queue[0];
    queue.push(String::from("job-3"));
    println!("working on {current}");
}
Output
error[E0502]: cannot borrow `queue` as mutable because it is also borrowed as immutable
 --> src/main.rs:4:5
  |
3 |     let current = &queue[0];
  |                    ----- immutable borrow occurs here
4 |     queue.push(String::from("job-3"));
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
5 |     println!("working on {current}");
  |                           ------- immutable borrow later used here

Why. push may reallocate the buffer, which would leave current dangling (see Mutable References).

Fix. Reorder so the reference is no longer used, or take an owned copy of what you need.

Rust
fn main() {
    let mut queue = vec![String::from("job-1"), String::from("job-2")];
    let current = queue[0].clone(); // an owned copy, not a borrow
    queue.push(String::from("job-3"));
    println!("working on {current}, {} queued", queue.len());
}
Output
working on job-1, 3 queued

5. Calling a &mut self method while iterating over a field (E0499)

Symptom. A very common shape: loop over a field and call another method on self inside the loop.

Rust✗ does not compile · E0499
struct Inventory {
    items: Vec<(String, u32)>,
    audit: Vec<String>,
}

impl Inventory {
    fn record(&mut self, message: String) {
        self.audit.push(message);
    }

    fn restock_empty(&mut self) {
        for (name, qty) in &mut self.items {
            if *qty == 0 {
                *qty = 10;
                self.record(format!("restocked {name}"));
            }
        }
    }
}

fn main() {
    let mut inv = Inventory { items: vec![(String::from("pen"), 0)], audit: Vec::new() };
    inv.restock_empty();
    println!("{:?}", inv.audit);
}
Output
error[E0499]: cannot borrow `*self` as mutable more than once at a time
  --> src/main.rs:15:17
   |
12 |         for (name, qty) in &mut self.items {
   |                            ---------------
   |                            |
   |                            first mutable borrow occurs here
   |                            first borrow later used here
...
15 |                 self.record(format!("restocked {name}"));
   |                 ^^^^ second mutable borrow occurs here

Why. self.record(...) borrows all of self mutably, including self.items, which the loop is already borrowing. The compiler checks method calls by their signatures, so it can't see that record only touches audit.

Fix. Borrow the fields directly. Field access is visible to the compiler, and different fields can be borrowed at the same time.

Rust
struct Inventory {
    items: Vec<(String, u32)>,
    audit: Vec<String>,
}

impl Inventory {
    fn restock_empty(&mut self) {
        for (name, qty) in &mut self.items {
            if *qty == 0 {
                *qty = 10;
                self.audit.push(format!("restocked {name}")); // borrows only `audit`
            }
        }
    }
}

fn main() {
    let mut inv = Inventory { items: vec![(String::from("pen"), 0), (String::from("ink"), 4)], audit: Vec::new() };
    inv.restock_empty();
    println!("{:?} {:?}", inv.items, inv.audit);
}
Output
[("pen", 10), ("ink", 4)] ["restocked pen"]

Another good fix is to collect the messages in a local Vec during the loop and call self.record for each one after it.

6. A getter keeps all of self borrowed (E0506)

Symptom. A getter returns a reference, and then another field is updated.

Rust✗ does not compile · E0506
struct Session {
    user: String,
    requests: u32,
}

impl Session {
    fn user(&self) -> &str {
        &self.user
    }

    fn handle(&mut self) {
        let who = self.user();
        self.requests += 1;
        println!("request #{} from {who}", self.requests);
    }
}

fn main() {
    let mut s = Session { user: String::from("ada"), requests: 0 };
    s.handle();
}
Output
error[E0506]: cannot assign to `self.requests` because it is borrowed
  --> src/main.rs:13:9
   |
12 |         let who = self.user();
   |                   ---- `self.requests` is borrowed here
13 |         self.requests += 1;
   |         ^^^^^^^^^^^^^^^^^^ `self.requests` is assigned to here but it was already borrowed
14 |         println!("request #{} from {who}", self.requests);
   |                                     --- borrow later used here

Why. self.user() returns a reference tied to all of self (elision rule 3), so self stays borrowed while who is alive.

Fix. Inside the type's own methods, use the field directly, which borrows only that field. Or finish the mutation before taking the reference.

Rust
struct Session {
    user: String,
    requests: u32,
}

impl Session {
    fn handle(&mut self) {
        let who = &self.user; // borrows only the `user` field
        self.requests += 1;
        println!("request #{} from {who}", self.requests);
    }
}

fn main() {
    let mut s = Session { user: String::from("ada"), requests: 0 };
    s.handle();
    s.handle();
}
Output
request #1 from ada
request #2 from ada

7. "cannot move out of ... because it is borrowed" (E0505)

Symptom. Handing a value to a new owner while a reference to it is still in use.

Rust✗ does not compile · E0505
fn archive(log: Vec<String>) -> usize {
    log.len()
}

fn main() {
    let log = vec![String::from("start"), String::from("stop")];
    let last = &log[log.len() - 1];
    let archived = archive(log);
    println!("archived {archived} lines, last was {last}");
}
Output
error[E0505]: cannot move out of `log` because it is borrowed
 --> src/main.rs:8:28
  |
6 |     let log = vec![String::from("start"), String::from("stop")];
  |         --- binding `log` declared here
7 |     let last = &log[log.len() - 1];
  |                 --- borrow of `log` occurs here
8 |     let archived = archive(log);
  |                            ^^^ move out of `log` occurs here
9 |     println!("archived {archived} lines, last was {last}");
  |                                                    ---- borrow later used here
  |
help: consider cloning the value if the performance cost is acceptable
  |
7 |     let last = &log.clone()[log.len() - 1];
  |                    ++++++++

Fix. Use the borrow before the move, or copy out what you need.

Rust
fn archive(log: Vec<String>) -> usize {
    log.len()
}

fn main() {
    let log = vec![String::from("start"), String::from("stop")];
    let last = log[log.len() - 1].clone();
    let archived = archive(log);
    println!("archived {archived} lines, last was {last}");
}
Output
archived 2 lines, last was stop

8. "cannot assign to ... because it is borrowed" (E0506)

Symptom. Replacing a value while a reference into it is still used.

Rust✗ does not compile · E0506
fn main() {
    let mut config = String::from("mode=dev");
    let mode = &config[5..];
    config = String::from("mode=prod");
    println!("started in {mode}");
}
Output
error[E0506]: cannot assign to `config` because it is borrowed
 --> src/main.rs:4:5
  |
3 |     let mode = &config[5..];
  |                 ------ `config` is borrowed here
4 |     config = String::from("mode=prod");
  |     ^^^^^^ `config` is assigned to here but it was already borrowed
5 |     println!("started in {mode}");
  |                           ---- borrow later used here

Why. Assigning a new value drops the old one, and mode points into the old one.

Fix. Finish using the reference first, or keep an owned copy.

Rust
fn main() {
    let mut config = String::from("mode=dev");
    let mode = config[5..].to_string();
    config = String::from("mode=prod");
    println!("started in {mode}, now {config}");
}
Output
started in dev, now mode=prod

9. "cannot move out of self.x which is behind a shared reference" (E0507)

Symptom. A getter that returns a field by value.

Rust✗ does not compile · E0507
struct Account {
    owner: String,
}

impl Account {
    fn owner(&self) -> String {
        self.owner
    }
}

fn main() {
    let a = Account { owner: String::from("Grace") };
    println!("{}", a.owner());
}
Output
error[E0507]: cannot move out of `self.owner` which is behind a shared reference
 --> src/main.rs:7:9
  |
7 |         self.owner
  |         ^^^^^^^^^^ move occurs because `self.owner` has type `String`, which does not implement the `Copy` trait
  |
help: consider cloning the value if the performance cost is acceptable
  |
7 |         self.owner.clone()
  |                   ++++++++

Why. &self only borrows the account, and you can't move something out of a borrow: the account would be left with no owner string.

Fix. Return a reference, or a clone if the caller really needs its own copy.

Rust
struct Account {
    owner: String,
}

impl Account {
    fn owner(&self) -> &str {
        &self.owner
    }

    fn owner_cloned(&self) -> String {
        self.owner.clone()
    }
}

fn main() {
    let a = Account { owner: String::from("Grace") };
    println!("{} / {}", a.owner(), a.owner_cloned());
}
Output
Grace / Grace

10. Moving an Option field out of &mut self (E0507)

Symptom. Consuming an optional field in a method that only has &mut self.

Rust✗ does not compile · E0507
struct Upload {
    pending_chunk: Option<Vec<u8>>,
    sent_bytes: usize,
}

fn send(chunk: Vec<u8>) -> usize {
    chunk.len()
}

impl Upload {
    fn flush(&mut self) {
        if let Some(chunk) = self.pending_chunk {
            self.sent_bytes += send(chunk);
        }
    }
}

fn main() {
    let mut u = Upload { pending_chunk: Some(vec![1, 2, 3]), sent_bytes: 0 };
    u.flush();
}
Output
error[E0507]: cannot move out of `self.pending_chunk` as enum variant `Some` which is behind a mutable reference
  --> src/main.rs:12:30
   |
12 |         if let Some(chunk) = self.pending_chunk {
   |                     -----    ^^^^^^^^^^^^^^^^^^
   |                     |
   |                     data moved here
   |                     move occurs because `chunk` has type `Vec<u8>`, which does not implement the `Copy` trait
   |
help: consider borrowing here
   |
12 |         if let Some(chunk) = &self.pending_chunk {
   |                              +

Fix. Option::take moves the value out and leaves None, which is exactly the state you want after sending.

Rust
struct Upload {
    pending_chunk: Option<Vec<u8>>,
    sent_bytes: usize,
}

fn send(chunk: Vec<u8>) -> usize {
    chunk.len()
}

impl Upload {
    fn flush(&mut self) {
        if let Some(chunk) = self.pending_chunk.take() {
            self.sent_bytes += send(chunk);
        }
    }
}

fn main() {
    let mut u = Upload { pending_chunk: Some(vec![1, 2, 3]), sent_bytes: 0 };
    u.flush();
    u.flush(); // nothing pending the second time
    println!("sent {} bytes, pending: {:?}", u.sent_bytes, u.pending_chunk);
}
Output
sent 3 bytes, pending: None

For non-Option fields, std::mem::take(&mut self.buffer) does the same, leaving an empty value behind.

11. "cannot return reference to local variable" (E0515)

Symptom. Building a value inside a function and returning a reference to it.

Rust✗ does not compile · E0515
fn display_name(user_id: &str) -> &str {
    let name = format!("user-{}", user_id.to_uppercase());
    &name
}

fn main() {
    println!("{}", display_name("a7f3"));
}
Output
error[E0515]: cannot return reference to local variable `name`
 --> src/main.rs:3:5
  |
3 |     &name
  |     ^^^^^ returns a reference to data owned by the current function

Fix. Return the owned value. There is nothing to borrow from once the function returns.

Rust
fn display_name(user_id: &str) -> String {
    format!("user-{}", user_id.to_uppercase())
}

fn main() {
    println!("{}", display_name("a7f3"));
}
Output
user-A7F3

12. "does not live long enough" when collecting references (E0597)

Symptom. Pushing references to values created inside a loop into a vector that lives outside it.

Rust✗ does not compile · E0597
fn main() {
    let raw = "alpha,BETA,Gamma";
    let mut normalized: Vec<&str> = Vec::new();
    for part in raw.split(',') {
        let lower = part.to_lowercase();
        normalized.push(&lower);
    }
    println!("{:?}", normalized);
}
Output
error[E0597]: `lower` does not live long enough
 --> src/main.rs:6:25
  |
3 |     let mut normalized: Vec<&str> = Vec::new();
  |         -------------- variable `normalized` declared here
4 |     for part in raw.split(',') {
5 |         let lower = part.to_lowercase();
  |             ----- binding `lower` declared here
6 |         normalized.push(&lower);
  |         ----------      ^^^^^^ borrowed value does not live long enough
  |         |
  |         borrow later used here
7 |     }
  |     - `lower` dropped here while still borrowed
  |
  = note: `normalized` is a collection that stores borrowed references, but `lower` does not live long enough to be stored in it
  = help: buffer reuse with borrowed references requires unsafe code or restructuring

Why. Each lower is dropped at the end of its iteration, while the vector keeps the reference.

Fix. Store owned values.

Rust
fn main() {
    let raw = "alpha,BETA,Gamma";
    let mut normalized: Vec<String> = Vec::new();
    for part in raw.split(',') {
        normalized.push(part.to_lowercase());
    }
    println!("{:?}", normalized);
}
Output
["alpha", "beta", "gamma"]

13. "temporary value dropped while borrowed" (E0716)

Symptom. Borrowing from a value that was never stored in a variable.

Rust✗ does not compile · E0716
fn read_line() -> String {
    String::from("id,name,email")
}

fn main() {
    let columns: Vec<&str> = read_line().split(',').collect();
    println!("{:?}", columns);
}
Output
error[E0716]: temporary value dropped while borrowed
 --> src/main.rs:6:30
  |
6 |     let columns: Vec<&str> = read_line().split(',').collect();
  |                              ^^^^^^^^^^^                     - temporary value is freed at the end of this statement
  |                              |
  |                              creates a temporary value which is freed while still in use
7 |     println!("{:?}", columns);
  |                      ------- borrow later used here
  |
help: consider using a `let` binding to create a longer lived value
  |
6 ~     let binding = read_line();
7 ~     let columns: Vec<&str> = binding.split(',').collect();
  |

Fix. Bind the temporary to a variable so it lives as long as the references into it.

Rust
fn read_line() -> String {
    String::from("id,name,email")
}

fn main() {
    let line = read_line();
    let columns: Vec<&str> = line.split(',').collect();
    println!("{:?}", columns);
}
Output
["id", "name", "email"]

14. "cannot borrow ... as mutable, as it is behind a & reference" (E0596)

Symptom. A function signature that says "read-only" while the body tries to write.

Rust✗ does not compile · E0596
fn add_default_role(roles: &Vec<String>) {
    if roles.is_empty() {
        roles.push(String::from("viewer"));
    }
}

fn main() {
    let mut roles = Vec::new();
    add_default_role(&roles);
    println!("{:?}", roles);
}
Output
error[E0596]: cannot borrow `*roles` as mutable, as it is behind a `&` reference
 --> src/main.rs:3:9
  |
3 |         roles.push(String::from("viewer"));
  |         ^^^^^ `roles` is a `&` reference, so it cannot be borrowed as mutable
  |
help: consider changing this to be a mutable reference
  |
1 | fn add_default_role(roles: &mut Vec<String>) {
  |                             +++

Fix. Ask for what the function needs: &mut.

Rust
fn add_default_role(roles: &mut Vec<String>) {
    if roles.is_empty() {
        roles.push(String::from("viewer"));
    }
}

fn main() {
    let mut roles = Vec::new();
    add_default_role(&mut roles);
    add_default_role(&mut roles);
    println!("{:?}", roles);
}
Output
["viewer"]

15. Changing self inside a match on one of its fields (E0502)

Symptom. Matching on a borrowed state field and calling a &mut self method in an arm.

Rust✗ does not compile · E0502
#[derive(Debug)]
enum State {
    Idle,
    Running { job: String },
}

struct Worker {
    state: State,
    completed: Vec<String>,
}

impl Worker {
    fn finish(&mut self, job: &str) {
        self.completed.push(job.to_string());
        self.state = State::Idle;
    }

    fn tick(&mut self) {
        match &self.state {
            State::Running { job } => self.finish(job),
            State::Idle => {}
        }
    }
}

fn main() {
    let mut w = Worker { state: State::Running { job: String::from("backup") }, completed: Vec::new() };
    w.tick();
}
Output
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
  --> src/main.rs:20:39
   |
19 |         match &self.state {
   |               ----------- immutable borrow occurs here
20 |             State::Running { job } => self.finish(job),
   |                                       ^^^^^------^^^^^
   |                                       |    |
   |                                       |    immutable borrow later used by call
   |                                       mutable borrow occurs here

Why. job borrows from self.state, and finish wants all of self, including the state it would overwrite while job still points into it.

Fix. Take the old state out with std::mem::replace, so job is owned, then decide on the new state.

Rust
#[derive(Debug)]
enum State {
    Idle,
    Running { job: String },
}

struct Worker {
    state: State,
    completed: Vec<String>,
}

impl Worker {
    fn tick(&mut self) {
        match std::mem::replace(&mut self.state, State::Idle) {
            State::Running { job } => self.completed.push(job), // `job` is owned now
            State::Idle => {}
        }
    }
}

fn main() {
    let mut w = Worker { state: State::Running { job: String::from("backup") }, completed: Vec::new() };
    w.tick();
    w.tick();
    println!("{:?} {:?}", w.state, w.completed);
}
Output
Idle ["backup"]

This "take the state out, compute the next state, put it back" pattern is how most state machines are written in Rust.

16. Returning a reference from inside a loop, then mutating (a known limitation)

Symptom. "Find it, or insert it" code that is actually safe, but is rejected by the current borrow checker.

Rust✗ does not compile · E0499
fn get_or_insert<'a>(names: &'a mut Vec<String>, name: &str) -> &'a mut String {
    for n in names.iter_mut() {
        if n == name {
            return n;
        }
    }
    names.push(name.to_string());
    names.last_mut().unwrap()
}

fn main() {
    let mut names = vec![String::from("ana")];
    get_or_insert(&mut names, "ben").push('!');
    println!("{:?}", names);
}
Output
error[E0499]: cannot borrow `*names` as mutable more than once at a time
 --> src/main.rs:7:5
  |
1 | fn get_or_insert<'a>(names: &'a mut Vec<String>, name: &str) -> &'a mut String {
  |                  -- lifetime `'a` defined here
2 |     for n in names.iter_mut() {
  |              ----- first mutable borrow occurs here
3 |         if n == name {
4 |             return n;
  |                    - returning this value requires that `*names` is borrowed for `'a`
...
7 |     names.push(name.to_string());
  |     ^^^^^ second mutable borrow occurs here

Why. The borrow for the early return is considered to last until the end of the function, even on the path where the loop finishes without returning. This is a known limitation (called "NLL problem case #3"). A future borrow checker, Polonius, will accept this code.

Fix. Find the index first, then create the one &mut you return.

Rust
fn get_or_insert<'a>(names: &'a mut Vec<String>, name: &str) -> &'a mut String {
    let index = match names.iter().position(|n| n == name) {
        Some(i) => i,
        None => {
            names.push(name.to_string());
            names.len() - 1
        }
    };
    &mut names[index]
}

fn main() {
    let mut names = vec![String::from("ana")];
    get_or_insert(&mut names, "ben").push('!');
    get_or_insert(&mut names, "ana").push('?');
    println!("{:?}", names);
}
Output
["ana?", "ben!"]

The HashMap entry API, covered in HashMap, solves the same problem for maps in one call.

A checklist for any borrow error

  1. Read the whole message. It names the borrow, where it starts, and where it is later used. The help: line is often the exact fix.
  2. Ask who owns the data. If a reference must outlive its source, the design needs an owned value.
  3. Look for a borrow that lasts longer than needed. Move the last use earlier, or copy out the small value you need.
  4. Look for a method call that borrows all of self. Borrow individual fields instead.
  5. Look for "a reference into a collection + a change to the collection". Use an index, or collect changes and apply them later.
  6. Use take, replace, and Option::take to move out of &mut.
  7. Clone as a last resort, and remember it is a real, visible cost.

This completes the Lifetimes section. Lifetime bounds, variance, higher-ranked trait bounds, and lifetimes in impl Trait, dyn Trait, and generic associated types are covered in Advanced Lifetimes, the first lesson of Advanced Rust, because they build on traits, closures, and trait objects.

Next is Traits.