user1206899
user1206899

Reputation: 1910

Why does compiler assert that the returned slice immutably borrow from s?

fn first_word(s: &str) -> &str {
    "there"
}

fn main() {
    let mut s = String::from("hello world");
    let word = first_word(&s);
    s.clear();
    println!("the first word is: {}", word);
}

The compiler complains:

error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable
 --> src/main.rs:8:5
  |
7 |     let word = first_word(&s);
  |                           -- immutable borrow occurs here
8 |     s.clear();
  |     ^^^^^^^^^ mutable borrow occurs here
9 |     println!("the first word is: {}", word);
  |                                       ---- immutable borrow later used here

I'm learning rust and this is a demo from the rust book which I changed a little bit. https://rust-book.cs.brown.edu/ch04-03-slices.html

I'm confused about the error message at the bottom line where it says word immutably borrows from s while logically this hasn't to be the case. Does the compiler always assume that the returned slice must point to the sole argument somehow? Does this have anything to do with lifetime? What is the general reasoning rule here?

Upvotes: 0

Views: 66

Answers (1)

Chayim Friedman
Chayim Friedman

Reputation: 70900

You're returning a string literal, &'static str. But the compiler never looks at function bodies while type checking - it only looks at their signatures.

first_word()'s signature is fn first_word(s: &str) -> &str, which by the lifetime elision rules is the same as fn first_word<'a>(s: &'a str) -> &'a str. So the compiler assumes the returned string borrows from the parameter string. It works because &'static str, which is actually returned, can be shortened to any other lifetime.

If you will declare first_word() as fn first_word(s: &str) -> &'static str then it'll work.

Upvotes: 3

Related Questions