There was more than enough time to learn why it was the right option to start with.
There was more than enough time to learn why it was the right option to start with.
arr[i as usize]
This is actually risky, because even when you only meant to extend, you can also accidentally truncate or change sign. `as` does all of these things without a warning, and mixed with type inference it can easily lead to surprises.Rust makes it worse by insisting on a theoretical support for 16-bit and 128-bit `usize` regardless of the target platform, so you can't use `a[i.into()]` to infallibly convert `u32` to `usize` on 32-bit and 64-bit platforms.
The correct syntax is:
arr[usize::try_from(i).unwrap()]
which is painfully verbose. In larger expressions it's almost an obfuscation of what the code is actually doing.I think unsignedness on array indices is one of those places where the “make invalid states unrepresentable” mantra has gone too far: yes it’s nice that theoretically the whole 64-bit index space is addressable from a byte array based at 0, but in reality -1 is just as stupid and invalid an array index as 2^64 - 1 for pretty much every use-case. What we gain is negligible; what we lose is a lot of sensible code for dealing with index arithmetic.
#[inline(always)]
fn idx(i : u32) { usize::try_from(i).unwrap() }
or #[inline(always)]
fn get(arr: [T], i : u32) { arr.[usize::try_from(i).unwrap()] }
Have to repeat the definition for each numeric type you use, I guess, but hopefully you aren't using _that_ many of them.Personally, I have datastructure that uses non `usize` indexes I usually wrap my vector/array in in a custom type that implements index on whatever my common index types are.
Because everything else is "let" in disguise. ML got the syntax right.