I find `usize` in Rust is like the default unsigned integer, used for nearly everything and especially everything index-related.
I do think in practice using `u64` instead of `usize` is meaningless, since there are so few 32-but systems today. The nice thing with the newtype pattern though is that if for whatever reason your program is going to run on a 32-bit instance and you need 64-bit IDs, it’s a 1-line change.
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}");
}
I see usize as the "memory indexing type" for the current platform I run on, storing it or sending it over some middleware should be a rare fringe case IMHO.
I do think in practice using `u64` instead of `usize` is meaningless, since there are so few 32-but systems today. The nice thing with the newtype pattern though is that if for whatever reason your program is going to run on a 32-bit instance and you need 64-bit IDs, it’s a 1-line change.