9
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)

Lukas Kalbertodt
  • 79,749
  • 26
  • 255
  • 305
jocull
  • 20,008
  • 22
  • 105
  • 149

1 Answers1

10

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

Vladimir Matveev
  • 120,085
  • 34
  • 287
  • 296
  • That helps to clarify. It's more of an annoyance than anything. So the error is related to a conflict between `truncate` needing mutability and `len` needing immutability? It would seem that `result.len()` would have its work completed before handing over to truncate, meaning this is more of a compiler quirk than anything? http://doc.rust-lang.org/std/string/struct.String.html#method.len – jocull May 29 '15 at 15:15
  • You're almost correct - the problem is that `truncate` requires `&mut self` which prohibits *any* subsequent borrowing in the same scope. And yes, it *would* seem that `result.len()` is completed before it is handed over to `truncate()`, however, my answer explains why it is not so - actually, the method receiver is computed *before* arguments, and so `&mut result` is in scope *before* `&result` required by `result.len()`. – Vladimir Matveev May 29 '15 at 15:23
  • @jocull, you can find more in the issues I've linked to in my update if you're interested in it. – Vladimir Matveev May 29 '15 at 15:34
  • Great information - thanks so much! Chalking it up to a compiler quirk that is just part of life for now. – jocull May 29 '15 at 15:48