Confused by usize and i32 for indexing into matrix!

Budding Rustacean here. I'm trying to update values inside a matrix based on some logic. The point is that I'm getting tripped up by the usize and i32 conflict that arises when indexing into my matrices row_counts and col_counts. The following is the error that keeps coming up:

error[E0277]: the type `[i32]` cannot be indexed by `&usize`
  --> src/lib.rs:48:21
   |
48 |                     row_counts[board_idx][r] += 1;
   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
   |
   = help: the trait `SliceIndex<[i32]>` is not implemented for `&usize`
   = note: required because of the requirements on the impl of `Index<&usize>` for `Vec<i32>`

error[E0277]: the type `[i32]` cannot be indexed by `&usize`
  --> src/lib.rs:49:21
   |
49 |                     col_counts[board_idx][c] += 1;
   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
   |
   = help: the trait `SliceIndex<[i32]>` is not implemented for `&usize`
   = note: required because of the requirements on the impl of `Index<&usize>` for `Vec<i32>`

error[E0277]: the type `[i32]` cannot be indexed by `&usize`
  --> src/lib.rs:50:24
   |
50 |                     if row_counts[board_idx][r] == 5 || col_counts[board_idx][c] == 5 {
   |                        ^^^^^^^^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
   |
   = help: the trait `SliceIndex<[i32]>` is not implemented for `&usize`
   = note: required because of the requirements on the impl of `Index<&usize>` for `Vec<i32>`

error[E0277]: the type `[i32]` cannot be indexed by `&usize`
  --> src/lib.rs:50:57
   |
50 |                     if row_counts[board_idx][r] == 5 || col_counts[board_idx][c] == 5 {
   |                                                         ^^^^^^^^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
   |
   = help: the trait `SliceIndex<[i32]>` is not implemented for `&usize`
   = note: required because of the requirements on the impl of `Index<&usize>` for `Vec<i32>`

For more information about this error, try `rustc --explain E0277`.

And this is the code that's causing this issue:

let num_boards = boards.len();
let mut row_counts: Vec<Vec<i32>> = vec![vec![0; 5]; num_boards]; // (num_boards x 5) matrix
let mut col_counts: Vec<Vec<i32>> = vec![vec![0; 5]; num_boards]; // (num_boards x 5) matrix

let (mut m1, mut m2) = (0, 0);
'outer: for draw in draws {
    for (board_idx, board) in boards.iter().enumerate() {
        match board.get(&draw) { // let mut boards: Vec<HashMap<i32, (usize, usize)>>;
            Some((r, c)) => {
                row_counts[board_idx][r] += 1;
                col_counts[board_idx][c] += 1;
                if row_counts[board_idx][r] == 5 || col_counts[board_idx][c] == 5 {
                    m1 = board_idx;
                    m2 = draw;
                    break 'outer;
                }
            }
            None => {}
        }
    }
}

Any help to solve this issue is appreciated! (BONUS: Any resources / blogs / docs that I can read to avoid making the above errors would be even more awesome, because I don't even understand why this error is happening)

The problem is that r and c are not integers, but references to integers.

1 Like

The consequent fix for what @alice said is to either write things like

row_counts[board_idx][*r] += 1;

or to introduce these variables with

Some(&(r, c)) => {

Indexing notation in Rust works with the ops::Index trait. Here, in row_counts[board_idx][r], the row_counts is a Vec<Vec<i32>>, and row_counts[board_idx] is a Vec<i32>. (Ignore the fact that this is another indexing-expression, too.) The indexing of this Vec<i32> by …[r] is interesting, in this case r is of type &usize, because HashMap::get returns a reference to the found value; and the pattern (r, c) matches a &(usize, usize) by introducing two references to the fields of the tuple.

Alternatively, taking a look at the error message, this part:

required because of the requirements on the impl of `Index<&usize>` for `Vec<i32>`

indicates clearly that we're trying to index a Vec<i32> with a &usize index.

Now, as noted in the error message,

slice indices are of type `usize` or ranges of `usize`

which includes indices of type usize or Range<usize> or RangeFrom<usize>, and a few more range types (the types corresponding to things like 0..10, 0..=10, ..10, and so on).

An indexing expression foo[bar] works by calling foo.index(bar), which (ignoring auto-dereferencing) generally only works when the types of the involved expressions, foo: Foo, and bar: Bar implement Foo: Index<Bar>.

You can look into the standard library docs for ops::Index to find an overview of all the implementations. For Vec<T>, you'll find

impl<T, I, A> Index<I> for Vec<T, A>
where
    I: SliceIndex<[T]>,
    A: Allocator, 

which refers us to yet-another trait which is used semi-internally in the standard library for indexing slices and vectors. If you click on that, you can find the complete list of supported index types in the form of this list:

impl<T> SliceIndex<[T]> for (Bound<usize>, Bound<usize>)
impl<T> SliceIndex<[T]> for usize
impl<T> SliceIndex<[T]> for Range<usize>
impl<T> SliceIndex<[T]> for RangeFrom<usize>
impl<T> SliceIndex<[T]> for RangeFull
impl<T> SliceIndex<[T]> for RangeInclusive<usize>
impl<T> SliceIndex<[T]> for RangeTo<usize>
impl<T> SliceIndex<[T]> for RangeToInclusive<usize>

The fact that there's no

impl<T> SliceIndex<[T]> for &usize

is why you're getting an error message.

3 Likes

Thanks for your answers @alice and @steffahn! Issue resolved. Thanks a lot for all this info on indexing in rust @steffahn !!