Lesson 4.3 · 11 min
Lending the key
Most functions only want to look at a message, not own it. Rust lets you lend a value with &, and the owner keeps the key. This lesson also shows the one thing a lender cannot do while the loan is out.
Adds to Chatterboxreply() borrows the message.
Lending instead of giving
You have seen the key move (lesson 4.2). Handing a key over every time a function wants to look at something would be exhausting: you would have to get it back each time. The second option is to lend it. The owner keeps the key. The borrower gets a reference, written with &, which lets it look but not take, and certainly not clean up.
Look at how little changes in the code. The function says what it needs with &str ("a borrowed piece of text"), and the caller says it is lending with &msg.
$ cargo run
HELLO / helloThe last line uses msg after shout has run. Under the rule from lesson 4.2 that would have been an error. It is fine here because shout only held a borrow. The key never left msg.
Step through the program. Solid arrows are ownership; dashed arrows are borrows. Use ← → or the slider.
- Line 5. The program starts in main.
- Line 6. msg is made and owns the text.
- Line 7. shout(&msg) lends msg. The dashed arrow is a borrow: it points at the text but owns nothing. msg still holds the key.
view:&strborrows bytes 0..5 ofmsg. - Line 2. shout reads the borrowed text and builds a brand new String, HELLO, that it will hand back by return.
- Line 3. shout ends. The loan is over, and because the borrower never owned the text, nothing is cleaned up. The new String's key goes to loud.
- Line 8. Both names are valid, so this prints HELLO / hello. stdout:
HELLO / hello
What a borrow costs you
A loan has one condition, and it is a natural one. While somebody is looking at a value, the owner may not change it. Imagine the owner rewriting the text while the borrower is mid-sentence. So long as there are shared borrowers, the room is read-only. You can have as many lookers as you like, but no editors.
How long is "while"? From the line where the reference is made to the last line where it is used. Not to the end of the block. Read this program and predict.
Does this compile — and if it does, does it run?
- It compiles and runs
- Compile error E0502
- It compiles, then panics
Reveal the answer
It does not compile: E0502. view is a borrow of transcript, and it is used again on the last line. push_str in between wants to change the text, which is not allowed while the loan is live.
error[E0502]: cannot borrow `transcript` as mutable because it is also borrowed as immutable --> src/main.rs:4:5 | 3 | let view = &transcript; | ----------- immutable borrow occurs here 4 | transcript.push_str(" there"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here 5 | println!("{view}"); | ---- immutable borrow later used here
Each bar is one borrow, drawn from its first use to its last. Scrub the line to see what is alive.
transcript: owner — owner, lines 1–6transcript: view = &transcript — shared borrow, lines 3–5transcript: push_str (changes it) — mutable borrow, lines 4–4
Each row is a value and each bar is a stretch of lines. The blue bar is the loan, drawn from first use to last use. The change on line 4 lands inside it, and that overlap is the error. Now the compiler's own words.
This is the exact output of the real compiler. Toggle the English, then pick a fix and see what actually happens.
error[E0502]: cannot borrow `transcript` as mutable because it is also borrowed as immutable --> src/main.rs:4:5 | 3 | let view = &transcript; | ----------- immutable borrow occurs here 4 | transcript.push_str(" there"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here 5 | println!("{view}"); | ---- immutable borrow later used here
E0502 in the compiler error atlas →
cannot borrow `transcript` as mutable because it is also borrowed as immutable: "mutable" means changing, "immutable" means just looking. You are changing something that is being looked at.immutable borrow occurs herepoints at&transcripton line 3: the loan begins.mutable borrow occurs herepoints atpush_stron line 4: someone tries to change it while the loan is out.immutable borrow later used herepoints at line 5: this is the use that keeps the loan alive. Without it there would be no error.
Fixes that were compiled for real
- Finish looking before you change — compiles. The last use of <code>view</code> is now before <code>push_str</code>, so the loan has ended. Free.
- Look at transcript itself afterwards — compiles. Drop the reference and print the owner after the change. You are not borrowing it at all anymore.
- Trap: using it again after the change — still E0502. Giving the reference a different name does not help if it is still used after the change. Only the last use counts, not what the name is.
Chatterbox v0.4
Now reply, a new shout and archive all borrow, and main still owns the one message. The new lines are marked. Note that the help text here is the short one; it grows in later lessons as commands are added.
$ cargo run
commands: /help, /quit
/HELP
[archived] /help
still mine: /helpWrite is_command, which borrows a message and says whether it starts with /. Text has a method starts_with(x) that answers exactly that: true when the text begins with x, and a single character goes in single quotes. After the call, the caller still owns the message.
Write is_command, which borrows a message and says whether it starts with /. Text has a method starts_with(x) that answers exactly that: true when the text begins with x, and a single character goes in single quotes. After the call, the caller still owns the message.
Hidden tests (4): empty_is_not_a_command plain_text_is_not slash_is_a_command works_on_a_borrowed_string
This exercise runs real Rust in your browser through the official Rust Playground, so it needs JavaScript.
Say it out loud, then reveal
What does & in front of a value do to ownership?Reveal
How long does a borrow last?Reveal
Why is changing a value while a shared borrow is still used refused?Reveal
That is lesson 4.3. Tick it off so the course remembers where you are.