How to borrow a value
Short answer: Put & in front of the value where you pass it (greet(&name)) and take a
reference in the receiving type (fn greet(who: &String)). The function then reads through a pointer
to the original instead of receiving the value itself, so nothing moves and your binding stays usable
afterwards.
The error & prevents
Section titled “The error & prevents”A parameter whose type is the value’s own type takes ownership of the argument. (The exception is
Copy types like i32, which are duplicated instead of moved.) The call moves the value in, and the
next line that mentions the caller’s variable stops compiling. From a fresh project — cargo new borrow-demo, then replace src/main.rs with the whole of this; the project name doesn’t matter,
because nothing in the output depends on it:
fn greet(who: String) { println!("hello, {who}");}
fn main() { let name = String::from("Ada");
greet(name); println!("hello again, {name}");}error[E0382]: borrow of moved value: `name` --> src/main.rs:9:29 |6 | let name = String::from("Ada"); | ---- move occurs because `name` has type `String`, which does not implement the `Copy` trait7 |8 | greet(name); | ---- value moved here9 | println!("hello again, {name}"); | ^^^^ value borrowed here after move |note: consider changing this parameter type in function `greet` to borrow instead if owning the value isn't necessary --> src/main.rs:1:15 |1 | fn greet(who: String) { | ----- ^^^^^^ this parameter takes ownership of the value | | | in this functionhelp: consider cloning the value if the performance cost is acceptable |8 | greet(name.clone()); | ++++++++ |For more information about this error, try `rustc --explain E0382`.The complaint is about name, not about greet. The call on the line above was the last place the
binding owned anything, so the println! is reading a value that has already moved. Cloning would
make the error go away; not moving in the first place is the cheaper fix.
Borrow it instead
Section titled “Borrow it instead”The fix is one & in the signature and one at the call site. Again the whole file:
fn greet(who: &String) { println!("hello, {who}");}
fn main() { let name = String::from("Ada");
greet(&name); println!("hello again, {name}");}hello, Adahello again, Ada&name is a reference to the String, and &String is its type. The same & shows up twice: once
at the call site, where it creates the reference, and once in the signature, where it declares what
the function expects. Inside greet, who points at the caller’s name — the text is not copied,
and name is exactly as usable after the call as it was before. Passing the value
by its own type instead is the move
version of this same call.
A borrow isn’t only for function calls. let reader = &name; binds a reference the same way, and the
original binding stays valid:
fn main() { let name = String::from("Ada"); let reader = &name;
println!("{reader}, then {name}");}Ada, then AdaWhat a borrow leaves alone
Section titled “What a borrow leaves alone”Borrowing changes neither what is freed nor when. A Drop implementation shows where the free
actually lands — again, a complete file:
struct Note(String);
impl Drop for Note { fn drop(&mut self) { println!("dropping {}", self.0); }}
fn read(note: &Note) { println!("reading {}", note.0);}
fn main() { let note = Note(String::from("shopping list"));
read(¬e); println!("done reading");}reading shopping listdone readingdropping shopping listThe drop happens at the end of main, exactly where it would have happened without the call at all:
read borrowed the value, so the owner’s scope still decides when it dies. Had read taken the
Note by value, dropping would have printed inside the call instead. That is the whole difference
a & makes — the function gets to look, and ownership stays where it was.
One limit is worth stating now, because it shapes every borrow you will write: a reference cannot
outlive the value it points at. How long a borrow counts as lasting is the subject of its own page
later in this chapter, and writing through a borrow — which needs &mut and a mut binding — is the
page after that.
Related
Section titled “Related”- How to pass ownership of a value to a function — the same call, taking the value instead
- How to fix error E0382: borrow of moved value — the error above, on its own page
- How to pass a Vec to a function without cloning it —
&[T], the borrow that works for any collection - Borrowing — the rest of this chapter
- Next in this chapter: what is the difference between
&and&mut?