errors2 solution

This commit is contained in:
mo8it 2024-06-26 15:36:14 +02:00
parent 2afe6b38d3
commit 050a23ce67
3 changed files with 71 additions and 13 deletions

View file

@ -2,16 +2,16 @@
// 5 tokens, and whenever you purchase items there is a processing fee of 1 // 5 tokens, and whenever you purchase items there is a processing fee of 1
// token. A player of the game will type in how many items they want to buy, and // token. A player of the game will type in how many items they want to buy, and
// the `total_cost` function will calculate the total cost of the items. Since // the `total_cost` function will calculate the total cost of the items. Since
// the player typed in the quantity, though, we get it as a string-- and they // the player typed in the quantity, we get it as a string. They might have
// might have typed anything, not just numbers! // typed anything, not just numbers!
// //
// Right now, this function isn't handling the error case at all (and isn't // Right now, this function isn't handling the error case at all (and isn't
// handling the success case properly either). What we want to do is: if we call // handling the success case properly either). What we want to do is: If we call
// the `total_cost` function on a string that is not a number, that function // the `total_cost` function on a string that is not a number, that function
// will return a `ParseIntError`, and in that case, we want to immediately // will return a `ParseIntError`. In that case, we want to immediately return
// return that error from our function and not try to multiply and add. // that error from our function and not try to multiply and add.
// //
// There are at least two ways to implement this that are both correct-- but one // There are at least two ways to implement this that are both correct. But one
// is a lot shorter! // is a lot shorter!
use std::num::ParseIntError; use std::num::ParseIntError;
@ -19,6 +19,8 @@ use std::num::ParseIntError;
fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> { fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
let processing_fee = 1; let processing_fee = 1;
let cost_per_item = 5; let cost_per_item = 5;
// TODO: Handle the error case as described above.
let qty = item_quantity.parse::<i32>(); let qty = item_quantity.parse::<i32>();
Ok(qty * cost_per_item + processing_fee) Ok(qty * cost_per_item + processing_fee)
@ -31,6 +33,7 @@ fn main() {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use std::num::IntErrorKind;
#[test] #[test]
fn item_quantity_is_a_valid_number() { fn item_quantity_is_a_valid_number() {
@ -40,8 +43,8 @@ mod tests {
#[test] #[test]
fn item_quantity_is_an_invalid_number() { fn item_quantity_is_an_invalid_number() {
assert_eq!( assert_eq!(
total_cost("beep boop").unwrap_err().to_string(), total_cost("beep boop").unwrap_err().kind(),
"invalid digit found in string" &IntErrorKind::InvalidDigit,
); );
} }
} }

View file

@ -660,12 +660,11 @@ One way to handle this is using a `match` statement on
`item_quantity.parse::<i32>()` where the cases are `Ok(something)` and `item_quantity.parse::<i32>()` where the cases are `Ok(something)` and
`Err(something)`. `Err(something)`.
This pattern is very common in Rust, though, so there's a `?` operator that This pattern is very common in Rust, though, so there's the `?` operator that
does pretty much what you would make that match statement do for you! does pretty much what you would make that match statement do for you!
Take a look at this section of the 'Error Handling' chapter: Take a look at this section of the "Error Handling" chapter:
https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator"""
and give it a try!"""
[[exercises]] [[exercises]]
name = "errors3" name = "errors3"

View file

@ -1 +1,57 @@
// Solutions will be available before the stable release. Thank you for testing the beta version 🥰 // Say we're writing a game where you can buy items with tokens. All items cost
// 5 tokens, and whenever you purchase items there is a processing fee of 1
// token. A player of the game will type in how many items they want to buy, and
// the `total_cost` function will calculate the total cost of the items. Since
// the player typed in the quantity, we get it as a string. They might have
// typed anything, not just numbers!
//
// Right now, this function isn't handling the error case at all (and isn't
// handling the success case properly either). What we want to do is: If we call
// the `total_cost` function on a string that is not a number, that function
// will return a `ParseIntError`. In that case, we want to immediately return
// that error from our function and not try to multiply and add.
//
// There are at least two ways to implement this that are both correct. But one
// is a lot shorter!
use std::num::ParseIntError;
fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
let processing_fee = 1;
let cost_per_item = 5;
// Added `?` to propagate the error.
let qty = item_quantity.parse::<i32>()?;
// ^ added
// Equivalent to this verbose version:
let qty = match item_quantity.parse::<i32>() {
Ok(v) => v,
Err(e) => return Err(e),
};
Ok(qty * cost_per_item + processing_fee)
}
fn main() {
// You can optionally experiment here.
}
#[cfg(test)]
mod tests {
use super::*;
use std::num::IntErrorKind;
#[test]
fn item_quantity_is_a_valid_number() {
assert_eq!(total_cost("34"), Ok(171));
}
#[test]
fn item_quantity_is_an_invalid_number() {
assert_eq!(
total_cost("beep boop").unwrap_err().kind(),
&IntErrorKind::InvalidDigit,
);
}
}