RustArena

Step 2 of 7

From text to numbers: parse

Input always arrives as text. When a user types 41, your program receives the characters '4' and '1' (and a newline), not the number 41. To do math, convert the text with parse:

use std::io;

fn main() {
    let mut line = String::new();
    io::stdin().read_line(&mut line).expect("failed to read a line");
    let age: u32 = line.trim().parse().expect("please type a whole number");
    println!("Next year you'll be {}", age + 1);
}
41
Next year you'll be 42

Here's what happens without trim:

use std::io;

fn main() {
    let mut line = String::new();
    io::stdin().read_line(&mut line).expect("failed to read a line");
    println!("read {:?}", line);
    let n: i32 = line.parse().expect("not a number");
    println!("{n}");
}
41
read "41\n"

The program panics, and the message starts with your text, followed by the reason:

not a number: ParseIntError { kind: InvalidDigit }

The newline counts as an invalid digit. That's why expect messages should say what was expected: it's the first thing you (or a teammate reading a crash report) will see.

The shadowing idiom

Reading into a String and then parsing into a variable with the same name is very common Rust. It's how the official Rust book's guessing game does it:

use std::io;

fn main() {
    let mut guess = String::new();
    io::stdin().read_line(&mut guess).expect("failed to read a line");
    let guess: u32 = guess.trim().parse().expect("please type a number");
    println!("You guessed {guess}, doubled that's {}", guess * 2);
}
21
You guessed 21, doubled that's 42

The text version isn't needed after parsing, so the number takes over its name.

Decimals

Parse into f64 for numbers with a fractional part: "3.5" works, and so does "7". The decimal separator must be a point: "3,5" fails. Parsing "3.5" into an integer type fails too.

Common mistakes

fn main() {
    let n = "42".trim().parse().expect("not a number");
    println!("{n}");
}
error[E0284]: type annotations needed

Fix: let n: i32 = ... or .parse::<i32>().

Your task

The program reads a temperature in Celsius (it may have decimals and may be negative). Parse it as an f64, convert it to Fahrenheit with F = C × 9 / 5 + 32, and print both: the Celsius value with a plain {} (so 0 prints as 0) and the Fahrenheit value with one decimal ({:.1}):

21.5 C = 70.7 F

Challenge 2

Read a number of minutes (a whole number) and print it as hours and minutes:

135 minutes = 2 h 15 min

Challenge 3

Read a year and say whether it's a leap year. A year is a leap year if it's divisible by 4, except years divisible by 100, which are leap years only if they're also divisible by 400. Print a line like 2024 is a leap year or 1900 is not a leap year, with the year that was read.

Previous: Reading a line with read_line Next: Reading several lines