Reputation: 23
I've been learning rust and I've been trying to learn the borrow checker works but i've come across this two examples that i don't understand why only one of those is considered borrowed :
fn main() {
let mut x = String::from("aa ab");
let y = first_word(&x);
x.clear(); //Error cannot borrow X
println!("{y}");
}
//Returns an i32 reference
fn first_word(s: &String) -> &i32 {
return &32;
}
fn main() {
let mut x = String::from("aa ab");
let y = first_word(&x);
x.clear(); //Everything is fine
println!("{y}");
}
//Returns an i32
fn first_word(s: &String) -> i32 {
return 32;
}
Is it possible for someone to explain why only the second one works?
Upvotes: 1
Views: 69
Reputation: 71899
Rust does not look into function to understand how they work on the outside. The function signature must contain all necessary information.
The signature fn first_word(s: &String) -> &i32
says "takes a reference to a string" (by the way, it's practically never useful to have a &String
, always use &str
instead), and return a reference to an int. But Rust also needs lifetime information, i.e. some bounds on how long the things behind the references live.
The way this works is a very simple process called lifetime elision. For "takes a reference, returns a reference", the sane assumption is that whatever is returned is somehow related to what's passed in, so the full signature becomes fn first_word<'a>(s: &'a String) -> &'a i32
.
This means that the compiler, when it sees a call to first_word
, will assume that as long as you keep the returned reference around (the y
in your code), the thing passed in is still borrowed.
Upvotes: 6