error[E0502]: cannot borrow `numbers` as immutable because it is also borrowed as mutable
--> <source>:6:36
|
6 | takes_slice_mut(&mut numbers[..numbers.len()-1]);
| ----------^^^^^^^---------
| | |
| | immutable borrow occurs here
| mutable borrow occurs here
| mutable borrow later used here
I usually fix it like this, but it looks silly coming from most other languages to extract an expression to a variable when it's only used once:
fn takes_slice_mut(_: &mut [f32]){}
fn main() {
let mut numbers = vec![0.0, -1.0, 3.0, 2.0, 0.5];
let len = numbers.len();
takes_slice_mut(&mut numbers[..len-1]);
}
Does anybody know a nicer way to resolve this?
Why does this bother the borrow checker anyway? I would think len() would return and release the borrow before the range describing the slice is created, but it seems like rustc is analyzing borrows only at the granularity of statements, not expressions? Can/will this be fixed someday?
There's a special case in the compiler that makes the borrow checker allow patterns like this, but it only applies to method call syntax. If you rewrite your code to use the index_mut method instead of x[i] syntax for indexing, it will compile:
use std::ops::IndexMut;
takes_slice_mut(numbers.index_mut(..numbers.len()-1));
For more explanation of why this requires special handling, see RFC 2025.
The RFC leaves open the possibility of expanding this special case to cover more types of code in the future, so it's possible that the compiler will eventually be able to compile your original code, too.
Thanks for linking to that RFC. I think it doesn't address the question as to why arguments aren't simply evaluated in the order that would make such common cases compile, i.e. self last. Is that because self is guaranteed to be evaluated first? (I know that for backwards compatibility reasons, argumenf evaluation order for free functions is quasi-guaranteed.)