rustborrow-checkerborrow

Why is this considered borrowed


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?


Solution

  • 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.