I tend to take the opposite approach in my Rust code. Unless I have a specific reason to use `usize` (e.g. using a type to index a standard library type that requires it), I always try to pick an exact size. It's pretty rare that I run into something where I'm either completely fine limiting the size to 32 bits or explicitly need to support something larger than that. Moreover, I'd still have to consider what happens at the limits of the integer type even if I did use `usize` for more general cases to make sure that I properly handle overflow (generally by using saturating or checked arithmetic in my use cases). Coincidentally, using usize only for stuff like indexing vectors and slices makes it much more rare I end up needing to explicitly deal with overflow for it because any time I have to make something dynamically sized, I already need to ensure that I'm putting reasonable limits on how much I'm willing to allocate, and that limit is inevitably much smaller than usize::MAX.
Moreover, I'd still have to consider what happens at the limits of the
integer type even if I did use `usize` for more general cases to make
sure that I properly handle overflow (generally by using saturating or
checked arithmetic in my use cases).
That's one of those things I don't particularly like about rust. The most terse means of converting between numeric types doesn't do any bounds checking.
use std::convert::TryFrom;
fn main() {
let a = usize::MAX;
let b = a as u32;
println!("{a} == {b}");
let c = u32::try_from(a).expect("this will always fail");
println!("{a} == {c}");
}