Darshak Parikh
Darshak Parikh

Reputation: 105

Why does this not count as an immutable borrow?

I am reading the official Rust Book and looking at listing 4-8 in Section 4.3.

The code looks like this:

fn first_word(s: &String) -> usize {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return i;
        }
    }

    s.len()
}

fn main() {
    let mut s = String::from("hello world");

    let word = first_word(&s);

    s.clear();
}

This line:

let word = first_word(&s);

seems to borrow an immutable reference to s. (This is where I guess I'm wrong; I just don't know why.)

In the next line, we mutate s by calling the clear() method.

I was expecting the compiler to throw:

cannot borrow `s` as mutable because it is also borrowed as immutable

Why does this compile?

Upvotes: 3

Views: 78

Answers (1)

Vittorio Romeo
Vittorio Romeo

Reputation: 93274

The string s is immutably borrowed for the duration of the call to first_word. As soon as the control is returned to main after first_word, the string is not considered borrowed anymore and can be mutated as you have observed.


If first_word were to return a &String which you extended the lifetime of by assigning it to a variable, then you would see the error you expected. E.g.

fn first_word(s: &String) -> &String {
    &s
}

fn main() {
    let mut s = String::from("hello world");
    let word = first_word(&s);
    s.clear();
}

cannot borrow s as mutable because it is also borrowed as immutable

https://rust.godbolt.org/z/cMVdVf

In that case, adding an extra scope would fix that:

fn main() {
    let mut s = String::from("hello world");

    {
        let word = first_word(&s);
    }

    s.clear();
}

Upvotes: 5

Related Questions