How to idiomatically convert between u32 and usize?

rust usize
convert usize to i32 rust
cast through a raw pointer first
rust convert usize to u64
rust u32
rust tryfrom
rust i32 to usize
slice indices are of type `usize` or ranges of `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 mismatch type 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 u32 type for variable n. How can I convert u32 to usize and use it in nth()?

The as operator works for all number types:

let ch = s.chars().nth(n as usize).unwrap();

Rust forces you to cast integers to make sure you're aware of signedness or overflows.

Integer constants can have a type suffix:

let n = 1u32;

However, note that negative constants, such as -1i32 is internally - 1i32.

Integer variables declared without an explicit type specification are shown as {integer} and will be properly inferred from one of the method calls.

5.29. Casting between types - Learn, For example, there is no way to convert an i64 into an i32 using the From trait, because fn try_from(u: i128) -> Result<usize, <usize as TryFrom<i128>>::Error​> [src][−] fn try_from(u: i16) -> Result<u32, <u32 as TryFrom<i16>>::Error> [src][​−]. I want to convert a usize typed variable into a u32 typed variable in Rust. I am aware that the usize variable might contain a value larger than 2^32, and in that case the conversion should fail. I

The most cautious thing you can do is to use TryFrom and panic when the value cannot fit within a 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);
}

By blindly using as, your code will fail in mysterious ways when run on a platform where usize is smaller than 32-bits. For example, some microcontrollers use 16-bit integers as the native 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
}

std::convert::TryFrom, Type Size Int Signed integers, machine-dependent Word Unsigned integers, machine-dependent Integer is special because of its ability to represent arbitrary-sized numbers via GNU Multiple Precision Arithmetic Library (GMP). However, there are idiomatic conventions in many situations. Float to convert between. 97. As the documentation states usize is pointer-sized, thus its actual size depends on the architecture your are compiling your program for. As an example, on a 32 bit x86 computer, usize = u32, while on x86_64 computers, usize = u64. usize gives you the guarantee to be always big enough to hold any pointer or any offset in a data structure, while u32 can be too small on some architectures.

We now have a pretty different answer when we try to compile your code, replacing the number 1 with a variable of type 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();
  |    

It means that now the compiler recommends you to use n.try_into().unwrap() that makes use of the trait TryInto which in turn relies on TryFrom and returns a Result<T, T::Error>. That's why we need to extract the result with a .unwrap()

TryInto documentation

Haskell High Performance Programming, The traits in std::convert provide a uniform API for converting values to In this article, we'll explore how to do it in a more idiomatic way converting an enum into an integer can be achieved with a cast, as we saw. Like the other traits in this module, they are used to implement conversions among types. Stack Overflow for Teams is a private, secure spot for you and your coworkers to find and share information. Learn more Rust: impl From<_> for usize, u64, u32, etc

Convenient and idiomatic conversions in Rust, Idiom #22 Convert string to integer. Extract integer value i from its string representation s (in radix 10). Illustration. Rust · Rust · Rust · Rust · Ada · C · Clojure  See also How to idiomatically convert between u32 and usize?; What's the difference between usize and u32?; Why is type conversion from u64 to usize allowed using as but not From?; How do I convert a usize to a u32 using TryFrom?. – Shepmaster Feb 27 at 17:08

Convert string to integer, in Rust, Idiom #79 Convert integer to floating point number. Declare floating point number y and initialize it with the value of integer x . Rust · C · Clojure · C++ · C# · D  The platform-dependent size of isize / usize is one reason why I'm asking this question - the original scenario was I wanted to convert from u32 to usize so I could represent a tree in a Vec<u32> (e.g. let t = Vec![0u32, 0u32, 1u32], then to get the grand-parent of node 2 would be t[t[2us] as usize]), and I wondered how it would fail if usize

Idiom #79 Convert integer to floating point number, In std::convert, there are automatic conversions, using the From trait, from u8 to TryFrom is available on nightly, and there is a u32 to usize conversion, so I'll Ropey can now convert between scalar value indices and utf16 code unit indices​. A usize is defined to be a "pointer-sized integer", which is usually the native size of the machine. On a 64-bit x64 processor, that means a usize is 64 bits, and on a 32-bit x86 processor, it will be 32 bits. Casting a usize to a i32 thus will operate differently depending on what type of machine you are running on.

Comments
  • What are some common use cases for converting usize to u32, and vice versa?
  • This is effectively already covered by an existing answer, as TryFrom / TryInto are mirrors of each other.