Question
In Rust, what is the difference between usize and u32?
The documentation describes usize as:
// Operations and constants for pointer-sized unsigned integers.
In many simple cases, replacing usize with u32 seems to work without changing program behavior. Because of that, it is unclear why Rust needs both types when they appear so similar.
Short Answer
By the end of this page, you will understand what usize means in Rust, how it differs from u32, and why both types exist. You will also learn when to use each one, especially for indexing, memory-related values, and data that must keep the same size across platforms.
Concept
usize and u32 are both unsigned integer types in Rust, but they are designed for different jobs.
u32is always a 32-bit unsigned integer.usizeis an unsigned integer whose size matches the platform's pointer size.
That means:
- On a 32-bit system,
usizeis 32 bits. - On a 64-bit system,
usizeis 64 bits.
Why usize exists
usize is used for values that describe things related to memory or indexing, such as:
- array and slice indices
- lengths of collections
- sizes in memory
- offsets into buffers
Rust uses usize for these because a program cannot index or address more memory than the machine's pointer size can represent.
For example:
let items = vec![10, 20, 30];
: = ;
(, items[i]);
Mental Model
Think of u32 as a standard shipping box with a fixed size no matter where you send it.
Think of usize as a box that changes size depending on the warehouse equipment. If the warehouse uses bigger lifting machines, the box can be bigger too.
In Rust:
u32is fixed-size everywhereusizeadapts to the machine's pointer size
Another way to think about it:
u32answers: How much data do I want this number type to store?usizeanswers: What size number makes sense for addressing/indexing memory on this machine?
So if you are counting bytes in memory or indexing into an array, usize fits naturally. If you are storing a fixed-format value like a file header field, u32 is the better match.
Syntax and Examples
In Rust, you can declare both types like this:
let a: u32 = 100;
let b: usize = 100;
Basic difference
fn main() {
let x: u32 = 5;
let y: usize = 5;
println!("x = {}, y = {}", x, y);
}
Both hold positive integers, but they are different types.
usize for indexing
fn main() {
let numbers = vec![10, 20, 30];
let index: usize = 1;
println!("{}", numbers[index]);
}
Step by Step Execution
Consider this example:
fn main() {
let data = [100, 200, 300, 400];
let i: usize = 2;
let value = data[i];
println!("{}", value);
}
Step by step:
datais created as an array with 4 elements.iis set to2and its type isusize.data[i]means: get the element at index2.- Rust accepts this because array indexing requires a
usize. - The value at index
2is300. println!prints300.
Now compare with u32:
Real World Use Cases
When to use usize
Indexing collections
let names = vec!["Ava", "Ben", "Cara"];
let idx: usize = 1;
println!("{}", names[idx]);
Working with lengths
let text = "hello";
let len: usize = text.len();
Buffer sizes and memory offsets
let buffer = vec![0u8; 1024];
let bytes: usize = buffer.len();
These values are tied to memory layout or container size.
When to use u32
File formats and protocols
Real Codebase Usage
In real Rust codebases, developers usually follow a simple rule:
- use
usizeat the boundaries of collections and memory operations - use fixed-width integers like
u32,u64, ori32for stored or transmitted data
Common patterns
1. Collection APIs return usize
let values = vec![1, 2, 3];
let count = values.len(); // usize
This avoids extra conversions when using lengths and indexes together.
2. Convert external numeric data when needed
fn get_item(items: &[String], id: u32) -> Option<&String> {
let index = usize::try_from(id).ok()?;
items.(index)
}
Common Mistakes
1. Using u32 for indexing directly
Broken code:
let items = vec![1, 2, 3];
let i: u32 = 1;
println!("{}", items[i]);
Why it fails:
- indexing expects
usize
Fix:
let items = vec![1, 2, 3];
let i: u32 = 1;
println!("{}", items[i as usize]);
Better fix when conversion may fail in a broader context:
let i: u32 = 1;
if let (index) = ::(i) {
(, items[index]);
}
Comparisons
| Type | Size | Platform-dependent | Best used for | Example |
|---|---|---|---|---|
u32 | 32 bits | No | Fixed-format numeric data | file headers, IDs, protocol fields |
usize | 32 or 64 bits | Yes | Indexing, lengths, memory sizes | vec.len(), array indices |
usize vs u64
| Type | Meaning |
|---|---|
usize |
Cheat Sheet
u32= always 32-bit unsigned integerusize= unsigned integer with the same size as a pointer- On 32-bit targets:
usizeis 32 bits - On 64-bit targets:
usizeis 64 bits
Use usize for
- array indexing
- slice indexing
len()values- buffer sizes
- memory offsets
Use u32 for
- file formats
- network protocols
- IDs
- binary data with fixed width
- cross-platform stored values
Important syntax
let a: u32 = 10;
let b: usize = 10;
let len: usize = my_vec.len();
: = ;
= my_vec[index ];
FAQ
Why does Rust use usize for indexing?
Because indexing is tied to memory addresses and collection sizes, which naturally match the machine's pointer size.
Is usize always the same as u64?
No. usize is u64 only on 64-bit targets. On 32-bit targets, it is 32 bits.
Can I replace usize with u32 in Rust?
Sometimes in small programs, but not generally. Many APIs expect usize, especially for indexing and lengths.
Why not use usize for everything?
Because usize changes size across platforms. That makes it a poor choice for file formats, network data, or any value that must have a fixed width.
Should I cast u32 to usize with as?
Only when you are sure the value fits. For safer code, prefer usize::try_from(...) when overflow or truncation is possible.
Is usize only for low-level programming?
Mini Project
Description
Build a small Rust program that stores user scores in a vector and looks up a score by a user-provided numeric ID. This project demonstrates when an external value might be u32, but indexing into a collection still requires usize.
It is practical because real programs often receive IDs or numbers from files, APIs, or user input as fixed-width integers, then use them to access in-memory collections.
Goal
Create a Rust program that accepts a u32 user ID, safely converts it to usize, and returns the matching score from a vector if the index is valid.
Requirements
- Create a vector of at least five scores
- Store the requested user ID as a
u32 - Convert the
u32ID tousizesafely - Use safe lookup with
.get()instead of direct indexing - Print a helpful message if the ID is out of range
Keep learning
Related questions
Accessing Cargo Package Metadata in Rust
Learn how to read Cargo package metadata like version, name, and authors in Rust using compile-time environment macros.
Associated Types vs Generic Type Parameters in Rust: When to Use Each
Learn when to use associated types vs generic parameters in Rust traits, with clear rules, examples, and practical API design advice.
Can a Struct Extend Another Struct in Rust? Composition vs Inheritance
Learn how Rust handles struct reuse without inheritance, using composition, traits, and wrapper structs with practical examples.