🎓 A1Learner
🔍

Rust Parsing Numbers

Number parsing turns text into a number in a chosen base or size. A failed parse names its reason.

parse is from_str in disguise

Both spellings run the same code. from_str needs the FromStr trait in scope:

use std::str::FromStr;
let n = i32::from_str("42").unwrap();
let m: i32 = "42".parse().unwrap();
println!("{} {}", n, m);

Read hex and binary text: from_str_radix

The second input is the base. Hex digits run past 9 into the letters a to f:

println!("{:?}", u32::from_str_radix("ff", 16));
println!("{:?}", u32::from_str_radix("1010", 2));

Prefixes are not digits

Text like 0xff carries a label the parser does not want. Strip it first, or the parse fails:

let hex = "0xff";
let digits = hex.strip_prefix("0x").unwrap();
println!("{:?}", u32::from_str_radix(digits, 16));
println!("{:?}", u32::from_str_radix("0xff", 16));

A minus sign is welcome, underscores are not

A sign belongs to the number. Underscores only decorate literals in your source code — in text read from outside, they are invalid digits:

println!("{:?}", i32::from_str_radix("-1010", 2));
println!("{:?}", i32::from_str_radix("1_000", 10));

Ask why it failed

Print the error with {:?}. It names the reason: too big for the type, or no text at all:

let too_big = "999999999999".parse::<i32>();
println!("{:?}", too_big);
let empty = "".parse::<i32>();
println!("{:?}", empty);

Floats read exponents and special words

A float parse accepts scientific notation, and even the special values by name:

println!("{}", "2.5e3".parse::<f64>().unwrap());
println!("{}", "inf".parse::<f64>().unwrap());

Example

fn main() {
    let colour = "0xFF8000";
    let hex_part = colour.strip_prefix("0x").unwrap();
    let value = u32::from_str_radix(hex_part, 16).unwrap();
    println!("colour value = {}", value);
    let binary = u32::from_str_radix("1111", 2).unwrap();
    println!("binary 1111 = {}", binary);
    let age: Result<u8, _> = "300".parse();
    println!("age 300 as u8 = {:?}", age);
    let temp: Result<i32, _> = "-12".parse();
    println!("temp = {:?}", temp);
}

Key points

  • parse is a thin front door: underneath, it calls from_str from the FromStr trait — and you can call Type::from_str(text) directly
  • Use Type::from_str_radix(text, radix) to read a number written in another base.
  • The radix may be from 2 to 36.
  • Strip prefixes yourself.
  • from_str_radix("0xff", 16) fails, because the 0x is not a digit.
  • Clean the text first, for example with strip_prefix.
  • A leading + or - sign is welcome in parsed text.
  • Underscores and spaces are not.
  • Underscores belong in literals you write in code, not in text read while running.
  • A failed parse names its reason.
  • Empty means empty text.
  • InvalidDigit means bad characters.
  • PosOverflow or NegOverflow means the number does not fit the type.
  • Floats parse more than digits.
  • "2.5e3" becomes 2500.0.
  • And "inf" and "NaN" become the special float values.
  • Real text arrives as hex inside a colour code or as binary from a sensor.
  • Number parsing reads text as a number in the base and size code asks for.

In this example, a web colour arrives as text. strip_prefix removes the 0x label, and from_str_radix with radix 16 reads the hex digits FF8000 as the number 16744448. The same function with radix 2 reads binary 1111 as 15. The last two lines keep the Result instead of unwrapping it. 300 cannot fit in a u8, so the parse reports PosOverflow. Meanwhile -12 fits an i32 easily and arrives as Ok(-12). Nothing crashed — every failure arrived as a value the program could inspect.

Note

The radix may go up to 36 because digits run 0–9 and then a–z: u32::from_str_radix("z", 36) is Ok(35).

Try it Yourself

Edit the code, then press Run.

Running is simulated · Rust Playground

Exercise

What does u32::from_str_radix("ff", 16) return?