Rust Type Casting
Rust won’t automatically convert one type into another for you — if you mix an i32 and an f64 in the same expression, it won’t compile. You have to convert explicitly. This is on purpose: silent conversions are a common source of bugs in other languages.
Converting between number types with as
Section titled “Converting between number types with as”Use the as keyword to cast one number type into another:
fn main() { let x: i32 = 10; let y: f64 = x as f64; // i32 -> f64
println!("{y}");}This matters more than it looks — try dividing two integers without casting, and you’ll get integer division instead of the decimal result you probably wanted:
fn main() { let a = 10; let b = 3;
println!("{}", a / b); // 3 (integer division) println!("{}", a as f64 / b as f64); // 3.3333333333333335}Casting down can lose data
Section titled “Casting down can lose data”Casting from a bigger type to a smaller one (like i32 to u8) doesn’t fail — it just truncates, which can give you a surprising result:
fn main() { let big: i32 = 300; let small = big as u8; // u8 only holds 0-255 println!("{small}"); // 44, not 300 — it wrapped around}Casting floats, characters and booleans
Section titled “Casting floats, characters and booleans”as works with a few more types than whole numbers. Each one has a rule worth knowing:
fn main() { println!("{}", 3.99_f64 as i32); // 3: the decimals are cut off println!("{}", -3.99_f64 as i32); // -3: cut toward zero, not down println!("{}", 3.99_f64.round() as i32); // 4: round first if you want that println!("{}", 300.0_f64 as u8); // 255: too big, so it stops at the max println!("{}", -5.0_f64 as u8); // 0: too small, so it stops at the min println!("{}", 'A' as u32); // 65: a char's code number println!("{}", 97_u8 as char); // a: and back again println!("{}", true as i32); // 1 (false would be 0)}Output:
3-34255065a1A few things to take away:
- Float to integer throws away everything after the decimal point. It doesn’t round. Call
.round()first if you want the nearest whole number. - Out-of-range floats are clamped to the nearest value that fits (
300.0becomes255in au8). That’s different from integers, which wrap around (300became44above). - Characters have a number behind them (their Unicode code point).
'A' as u32gives65. Only au8can be cast straight back to achar; for bigger numbers you’d usechar::from_u32, because not every number is a valid character. - Booleans turn into
1or0. The other direction doesn’t work:1 as boolwon’t compile. Use a comparison liken != 0instead.
Parsing strings into numbers
Section titled “Parsing strings into numbers”Casting with as only works between number types. To turn text into a number — say, something typed by a user — use .parse():
fn main() { let text = "42"; let number: i32 = text.parse().expect("not a valid number");
println!("{}", number + 8);}Output:
50.parse() can fail (what if the text isn’t a number at all?), so it returns a Result rather than the number directly. We haven’t covered Result yet — for now, .expect("message") is a simple way to say “crash with this message if it fails.” You’ll see the proper way to handle it on the Result page.
Numbers into strings
Section titled “Numbers into strings”Going the other way is simpler — almost every type can turn into a String with .to_string():
fn main() { let number = 42; let text = number.to_string(); println!("{}", text + "!");}Practice
Section titled “Practice”1. Average score
Section titled “1. Average score”Store three test scores as i32 values: 7, 8 and 10. Print their sum, then their average with two decimal places. Hint: if you divide two integers you get 8, not 8.33, so cast the sum to f64 first. {:.2} prints two decimals.
Show solution
fn main() { let a: i32 = 7; let b: i32 = 8; let c: i32 = 10;
let sum = a + b + c; let average = sum as f64 / 3.0; // 25.0 / 3.0, not 25 / 3
println!("sum: {sum}"); println!("average: {:.2}", average);}Output:
sum: 25average: 8.332. Price from text
Section titled “2. Price from text”A shop gives you the price as text, "4.50", and the quantity as an i32, 3. Turn the text into an f64, multiply by the quantity, and print Total: 13.5. Hint: you need both tools from this page: .parse() for the text and as f64 for the quantity.
Show solution
fn main() { let price_text = "4.50"; let quantity: i32 = 3;
let price: f64 = price_text.parse().expect("not a valid price"); let total = price * quantity as f64; // f64 * f64
println!("Total: {total}");}Output:
Total: 13.5Without as f64, Rust would refuse to multiply an f64 by an i32, because it never mixes number types for you.
- Rust never converts types automatically — you always cast explicitly.
- Use
asto convert between number types:x as f64,x as u8. - Casting down to a smaller type truncates silently — it won’t error, so be careful.
- Float to integer cuts off the decimals (use
.round()first to round).charandboolcan be cast to numbers too. - Use
.parse()to turn text into a number, and.to_string()to go the other way.
Quick check
Section titled “Quick check”Quick check
1. What happens when you divide two integers like 10 / 3 in Rust without casting?
2. What happens when you cast 300_i32 as u8?
3. What does .parse() return when converting a string to a number, since the conversion can fail?
Score: 0 / 3
Read more
Section titled “Read more”- Casting — Rust by Example: many runnable
ascasts, with comments on exactly what each one produces. - Type cast expressions — The Rust Reference: the full table of which casts are allowed and the precise rule for each.
- To and from Strings — Rust by Example:
.to_string()and.parse()in a little more depth. TryFrom— standard library docs: the checked conversion (u8::try_from(...)) to use when a value might not fit.- Numeric Types — The Rust Reference: the size and range of every integer and float type.