Search code examples
rustimmutabilitymutabilityborrow-checker

Cannot borrow as immutable - String and len()


let mut result = String::with_capacity(1000);

result.push_str("things... ");
result.push_str("stuff... ");

result.truncate((result.len() - 4));

However, this is a compile error. Something to do with the borrow checker and possibly mutability.

error[E0502]: cannot borrow `result` as immutable because it is also borrowed as mutable
 --> <anon>:7:22
  |
7 |     result.truncate((result.len() - 4));
  |     ------           ^^^^^^           - mutable borrow ends here
  |     |                |
  |     |                immutable borrow occurs here
  |     mutable borrow occurs here

Yet, if I change it slightly I am allowed to do this:

let newlen = result.len() - 4;
result.truncate(newlen);

Why? Is there a way to change this so it can be written in one line? (P.S. this is on Rust 1.0)


Solution

  • This is an unfortunate shortcoming of Rust borrow checking procedure. This essentially happens because

    result.truncate(result.len() - 2)
    

    is equivalent to

    String::truncate(&mut result, result.len() - 2)
    

    and here you can see that because arguments are computed in left-to-right order, result is indeed borrowed mutably before it is used in result.len().

    I found this problem in Rust issue tracker: #6268. This issue was closed in favor of non-lexical borrows RFC issue. It seems that it's just one of those things which would be nice to have but which needed more time to be done that it was available before 1.0. This post may also be of some interest (even though it is almost two years old).