Indexing syntax borrow checking should work as with functions

I often want to access elements in a slice from the end:

&mut slice[ slice.len() - index ]

However, borrow checker complains:

cannot borrow slice as immutable because it is also borrowed as mutable

If I use a method (IndexMut::index_mut or .get_mut(slice.len() - index).unwrap()), then everything is fine.

Therefore, I think the indexing syntax should work the same.

1 Like

This is "two phase borrows," if you want the key phrase to search for. It is definitely odd that it doesn't apply here to indexing syntax.

3 Likes

This compiles successfully in the current stable Rust toolchain (playground):

pub fn foo<T>(slice: &mut [T], index: usize) -> &mut T {
    &mut slice[slice.len() - index]
}

Can you give a complete example that does not compile?

1 Like

This issue is related:

A &mut [T] looks to work but a Vec<T> fails (playground)

pub fn foo<T>(slice: &mut Vec<T>, index: usize) -> &mut T {
    // let slice : &mut [T] = slice; 
    &mut slice[slice.len() - index]
}
7 Likes

It appears two phase borrows don't apply when DerefMut is involved, even for methods instead of indexing.

Which makes sense: normally a two-phase borrow needs to be "activated" only immediately before the method is called, but with DerefMut involved the borrow must be mutable straight away to pass to deref_mut, before the other arguments are evaluated.

(But apparently Box behaves differently, probably because dereferencing a Box doesn't use DerefMut.)

1 Like

I made a little crate for doing that a few years back that you could play with. It would allow your example as &mut slice.rev()[index] (assuming you meant &mut slice[slice.len()-(index+1)] in your example, so that index == 0 isn't out-of-bounds).

2 Likes

Arrays (as well as Vec, mentioned by Jon-Davis) might be treated differently than slices: Playground