How to idiomatically convert between u32 and usize?
This code works and prints "b":
fn main() {
let s = "abc";
let ch = s.chars().nth(1).unwrap();
println!("{}", ch);
}
On the other hand, this code results in a type mismatch error.
fn main() {
let s = "abc";
let n: u32 = 1;
let ch = s.chars().nth(n).unwrap();
println!("{}", ch);
}
error[E0308]: mismatched types --> src/main.rs:5:28 | 5 | let ch = s.chars().nth(n).unwrap(); | ^ expected usize, found u32
For some external reason, I have to use the type u32
for the variable n
. How can I convert u32
to usize
and use it to nth()
?
source to share
The operator as
works for all types of numbers:
let ch = s.chars().nth(n as usize).unwrap();
Rust forces you to enter integers to make sure you are aware of signatures or overflows.
Integer constants can have a suffix like:
let n = 1u32;
Note, however, that negative constants such as -1i32
are internal -
1i32
.
Integer variables declared without an explicit type specification are displayed as {integer}
and will be correctly inferred from one of the method calls.
source to share
The most careful thing you can do is use TryFrom
and panic when the value cannot fit in usize
:
use std::convert::TryFrom;
fn main() {
let s = "abc";
let n: u32 = 1;
let n_us = usize::try_from(n).unwrap();
let ch = s.chars().nth(n_us).unwrap();
println!("{}", ch);
}
Blindly used, as
your code will mysteriously fail when run on a platform usize
less than 32-bit. For example, some microcontrollers use 16-bit integers as their own size:
fn main() {
let n: u32 = 0x1_FF_FF;
// Pretend that 'usize' is 16-bit
let n_us: u16 = n as u16;
println!("{}, {}", n, n_us); // 131071, 65535
}
source to share
We now have a completely different answer when we try to compile your code by replacing the number 1
with a variable like i32
:
error[E0308]: mismatched types --> src/main.rs:5:28 | 5 | let ch = s.chars().nth(n).unwrap(); | ^ expected usize, found i32 help: you can convert an 'i32' to 'usize' and panic if the converted value wouldn't fit | 5 | let ch = s.chars().nth(n.try_into().unwrap()).unwrap(); |
This means that the compiler now recommends using n.try_into().unwrap()
that uses a trait TryInto
, which in turn relies on TryFrom
and returns Result<T, T::Error>
. This is why we need to extract the result with.unwrap()
source to share