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);
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_stringproduces aStringfrom any number that implementsDisplay(every primitive does).format!builds aStringfrom a template, e.g.format!("{n}").
Display (and u32 does) can be turned into
a String with one method call.to_string on the integer types, or the format! macro.fn number_to_string(number: u32) -> String {
number.to_string()
}
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:
100.0).f64, because Rust won't mix the two for you.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
asis the cast operator.1.7_f64 as u32is1(truncation), not2. That same truncation is what drops fractional HP in this exercise.f64::roundexists 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.
base + base * (bonus_percent / 100.0).base is u32 and bonus_percent is f64. You can't
multiply them directly. Cast base with as f64 first.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.fn damage_with_bonus(base: u32, bonus_percent: f64) -> u32 {
(base as f64 + base as f64 * (bonus_percent / 100.0)) as u32
}
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::parseturns a string into any type that implementsFromStr. Returns aResultbecause the input might not be valid.Result::unwrap_orhands back the value onOk, or the fallback you give it onErr. Useful for the "just give me a number" path here.
&str has a .parse() method that can produce many number types.
You'll need a type annotation so it knows which one..parse::<u32>() returns a Result<u32, _>. The exercise asks for
0 on failure, so reach for .unwrap_or(0).Result
directly is the better signature.)fn parse_positive_integer(input: &str) -> u32 {
input.parse::<u32>().unwrap_or(0)
}
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
asfor a truncating cast, or.into()/.try_into()when you want a checked conversion.format!andto_string()produce aStringfrom any value that implementsDisplay.f64::round()rounds to the nearest integer;as u32on its own truncates. They give different answers for1.7. We usedas u32for 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 aResult; pair it with.unwrap_or(...)until you've metResultproperly in chapter 11.- For arithmetic that might overflow,
checked_add/checked_sub/checked_mulreturn anOption<T>instead of panicking. Worth remembering once you stop trusting your inputs.