Chapter 1

Numbers in Rust

👋 Anyone can read and edit this exercise. Sign up to save your progress.

This chapter was supposed to start with an integer joke. Turns out, it's pointless.

Rust has many integer types. The most common ones are i32 (signed, 32-bit) and u32 (unsigned, 32-bit). The u versions can't be negative. For sizes and indices you'll usually see usize. Floating-point comes in two flavors: f32 and f64. There's no implicit conversion between numeric types in Rust, so you'll often write as casts or use .into() when types need to meet.

A small example to ground the syntax:

let count: u32 = 42;
let price: f64 = 19.99;
let total = price * count as f64; // explicit cast

Parsing strings into numbers returns a Result, since the input might not actually be a number. For now, match or .unwrap_or(0) is enough to handle that.

let n: u32 = "123".parse().unwrap_or(0);

Number to string

Start with the simplest direction: take a number, hand back its textual form. Rust's standard library has a one-shot method for this on every primitive integer type, and the format! macro from chapter 0 works too. Either is fine.

Useful from the standard library

  • u32::to_string produces a String from any number that implements Display (every primitive does).
  • format! builds a String from a template, e.g. format!("{n}").
Exercise 1 of 3
Open in Web Editor

Results

    Compiler / runtime output
    
                
    Stuck? Show a hint No spoilers, just a nudge
    1. Every type that implements Display (and u32 does) can be turned into a String with one method call.
    2. Look for to_string on the integer types, or the format! macro.
    3. fn number_to_string(number: u32) -> String {
          number.to_string()
      }
      

    `damage_with_bonus`

    Rust never converts between numeric types implicitly. If you want to multiply a u32 by an f64, one of them has to change shape first, and you have to say so. The as keyword does the conversion.

    The function takes a base damage as u32 and a bonus as an f64 percentage (so 50.0 means "+50%"; think a critical hit, an equipment buff, or any other damage modifier), and returns the final damage as a u32. You'll need to:

    1. Turn the percentage into a multiplier (divide by 100.0).
    2. Multiply it by the base, but only after casting the base to f64, because Rust won't mix the two for you.
    3. Add the bonus to the base.
    4. Cast back to u32 to return.

    That last cast truncates the fractional part toward zero, which is exactly what we want here: most games quantise to whole HP, so 8.085 damage becomes 8, not 9. The final test pins this down.

    Useful from the standard library

    • as is the cast operator. 1.7_f64 as u32 is 1 (truncation), not 2. That same truncation is what drops fractional HP in this exercise.
    • f64::round exists too, and rounds to the nearest integer. It's the right tool when you want nearest-integer rounding, but this exercise asks for truncation, so you won't need it here.
    Exercise 2 of 3
    Open in Web Editor

    Results

      Compiler / runtime output
      
                  
      Stuck? Show a hint No spoilers, just a nudge
      1. The maths is base + base * (bonus_percent / 100.0).
      2. base is u32 and bonus_percent is f64. You can't multiply them directly. Cast base with as f64 first.
      3. To go back to u32 for the return value, use a plain as u32 cast. That truncates the fractional part (drops any fractional HP), which is what the 15.5% test pins down.
      4. fn damage_with_bonus(base: u32, bonus_percent: f64) -> u32 {
            (base as f64 + base as f64 * (bonus_percent / 100.0)) as u32
        }
        

      Parsing strings into numbers

      str::parse is the universal "turn this text into a value of some type" method. It returns a Result, because the input might not be parseable. We don't have Result yet (that's chapter 11), so we'll collapse failure to 0 for now.

      Returning 0 on failure is a bad idea in real code: it silently merges "the input was the number zero" with "the input was garbage". Rust has a much better tool for this in Option (chapter 10) and Result (chapter 11). For now, parse().unwrap_or(0) is the shortest way to satisfy the tests.

      Note that u32 can't be negative, so "-5".parse::<u32>() will fail and we should also return 0. If you reach for i32 first, the test for "-5" may surprise you.

      Useful from the standard library

      • str::parse turns a string into any type that implements FromStr. Returns a Result because the input might not be valid.
      • Result::unwrap_or hands back the value on Ok, or the fallback you give it on Err. Useful for the "just give me a number" path here.
      Exercise 3 of 3
      Open in Web Editor

      Results

        Compiler / runtime output
        
                    
        Stuck? Show a hint No spoilers, just a nudge
        1. &str has a .parse() method that can produce many number types. You'll need a type annotation so it knows which one.
        2. .parse::<u32>() returns a Result<u32, _>. The exercise asks for 0 on failure, so reach for .unwrap_or(0).
        3. (Forward reference: in chapter 11 you'll learn why returning Result directly is the better signature.)
        4. fn parse_positive_integer(input: &str) -> u32 {
              input.parse::<u32>().unwrap_or(0)
          }
          

        Wrapping up numbers

        Congratulations! You converted numbers to strings, mixed integers with floats (carefully), and turned text back into a number. The pattern "convert, then operate" is very helpful for your future work with numbers.

        What we learned

        • Rust never converts between numeric types implicitly. Use as for a truncating cast, or .into() / .try_into() when you want a checked conversion.
        • format! and to_string() produce a String from any value that implements Display.
        • f64::round() rounds to the nearest integer; as u32 on its own truncates. They give different answers for 1.7. We used as u32 for the damage-bonus calculation because we wanted truncation; fractional HP is simply dropped, the way most games quantise damage.
        • str::parse() is the universal text-to-value method. It returns a Result; pair it with .unwrap_or(...) until you've met Result properly in chapter 11.
        • For arithmetic that might overflow, checked_add / checked_sub / checked_mul return an Option<T> instead of panicking. Worth remembering once you stop trusting your inputs.
        Next chapter 2Strings, &str, and Chars