Search code examples
rustmutableborrowing

Why Rust mutable borrow occurs here?


I'm learning Rust and the below code comes from the online book The Rust Programming Language.

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

    let word = first_word(&s);

    s.clear(); // error!

    println!("the first word is: {}", word);
}


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

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

    &s[..]
}

When I run it, I get this:

C:/Users/administrator/.cargo/bin/cargo.exe run --color=always --package rust2 --bin rust2
   Compiling rust2 v0.1.0 (C:\my_projects\rust2)
error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable
 --> src\main.rs:6:5
  |
4 |     let word = first_word(&s);
  |                           -- immutable borrow occurs here
5 | 
6 |     s.clear(); // error!
  |     ^^^^^^^^^ mutable borrow occurs here
7 | 
8 |     println!("the first word is: {}", word);
  |                                       ---- immutable borrow later used here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0502`.
error: could not compile `rust2`.

To learn more, run the command again with --verbose.

Process finished with exit code 101

But as I understand, s is just a mutable String object. s.clear() is simply invoking a method on the object and this generates a mutable borrow error? A mutable borrow is something like let mut a = &mut s. The statement s.clear() is using s directly, where does the borrow come from?


Solution

  • The statement s.clear() is using s directly, where does the borrow come from?

    A method's first parameter is always self, which represents the instance of the struct the method is being called on. If one doesn't want to take ownership, and just reads data in the struct but not writes to it, then one can choose &self. If on the other hand, one wants to change the instance that is called method on, then one would choose &mut self. Last but not the least, self takes the ownership and usually is transformed into something else.

    Here, the String::clear is defined as:

    pub fn clear(&mut self)
    

    It is a mutable borrow. If calling clear method another way, you can clearly see why:

    let word = first_word(&s);
    String::clear(&mut s);
    println!("the first word is: {}", word);