Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is borrowing a &mut reference from an immutable array sometimes possible?

Tags:

rust

Let's try to compile this code:

trait Bar {
    fn bar(&mut self);
}

fn foo(a1: &mut Bar, j: usize) {
    let a = [a1];
    a[0].bar(); //compilation ok
    a[j % 2].bar();
}

fn main() {}

Compilation error:

error[E0596]: cannot borrow immutable local variable `a` as mutable
 --> src/main.rs:8:5
  |
6 |     let a = [a1];
  |         - consider changing this to `mut a`
7 |     a[0].bar(); //compilation ok
8 |     a[j % 2].bar();
  |     ^ cannot borrow mutably

Why is a[0].bar() OK, but a[j % 2].bar() fails? Is it a compiler bug?

like image 981
chabapok Avatar asked Nov 19 '17 08:11

chabapok


1 Answers

Is it a compiler bug?

Yes. It is fixed in Rust 1.25.0-nightly (2018-01-09 61452e506f0c88861cccaeea4ced3419bdb3cbe0) by PR 47167

The short version is that there are two ways of performing indexing, referred to as "builtin indexing" and "overloaded indexing". As you might be able to guess from the names, one is more intrinsic to the compiler and the other is more user-customizable.

In this case, the overloaded indexing is performing an unneeded borrow of the array, triggering the warning. You can work around the problem by simplifying the compilers job of type inference:

fn foo(a1: &mut Bar, j: usize) {
    let a = [a1];
    let x: usize = j % 2;
    a[x].bar();
}

By explicitly stating the index is a usize, the code will now use the builtin indexing.

like image 162
Shepmaster Avatar answered Nov 15 '22 07:11

Shepmaster