Why can I get data by index for VEC data type usize instead of u*?

Hello experts, here I have a question about the program implementation, I want to access the contents of the Vec array via by using variables. But when I use u32 as the type of the index variable, the VSCode compiler always tells me that slice indices are of type 'usize' or ranges of 'usize', but when I compile with the usize type, it passes, and I wonder why, if my program has an error or something else

let number_list: Vec<i32> = vec![34, 50, 25, 100, 65];
let length: u32 = number_list.len().try_into().unwrap();
let mut index: u32 = 0;
println!("{:#?}", number_list[index]);
=======================================
>>number_list[index]
    ^^^^^slice indices are of type `usize` or ranges of `usize`

let number_list: Vec<i32> = vec![34, 50, 25, 100, 65];
let length: usize = number_list.len().try_into().unwrap();
let mut index: usize = 0;
println!("{:#?}", number_list[index]);

There isn't much to explain here. Slices and other array-like collections intentionally only implement Index<usize> and not Index<any other integer type>. That's in fact the whole point of usize: it's the type that is guaranteed to accommodate all possible indices, pointer offsets, etc. on the target platform. Since this is platform-dependent, no fixed-width integer can possibly fulfill this role. (E.g., a u32 may not be enough on a 64-bit platform, and a u64 may be too big on a 32-bit platform.)

3 Likes

Ok! Thank you for help...

Another reason is that implementing for multiple integer types makes the type of literals in that position ambiguous, in which case inference falls back to i32 (which is not a valid indexing type).

2 Likes

You could make i32 a valid indexing type. But then the concern is that it may silently break code because what was previously deduced as usize now might be deduced as i32.

Yeah, I worded that poorly. (Also there's no agreement on how to treat negative indices.)

1 Like

I think this one would be relatively easy to resolve. The general "prefer loud errors to stumbling along" policy and the efficiency details of bounds checking both say that negative indices should be out-of-range panics.

(That would make indexing by isize take exactly the same machine code as indexing by usize, including in the bounds check, for slices of non-ZSTs which are the only slices where efficiency actually matters.)

I'm not going to bother tracking down citations, but others would prefer indexing backwards as is done in various other languages, and my impression from the conversations I've read is as I said -- no agreement.

The Rust way to do this would be to use a newtype for indexing from the end rather than treating negative numbers differently from positive numbers:

a[EndMinus(10)]
a[10..][..EndMinus(3)]
2 Likes

And doing something other than "make negatives work" is also the C# way (https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#index-from-end-operator-) and the D way (https://dlang.org/spec/expression.html#IndexOperation).

Having an off-by-one error give you the last element instead of an error is a very scripting language thing, IMHO.

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.