Created
October 6, 2018 18:11
-
-
Save totechite/5f23267178c4defda21f0eebcf26d49e to your computer and use it in GitHub Desktop.
Practice Error Handling on rustlings.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 number of tokens. | |
// Since the player typed in the quantity, though, we get it as a string-- and | |
// 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 `parse` function on a string that is not a number, that | |
// function will return a `ParseIntError`, and 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! Scroll down for hints to both ways. | |
use std::num::ParseIntError; | |
pub fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> { | |
let processing_fee = 1; | |
let cost_per_item = 5; | |
let qty = item_quantity.parse::<i32>(); | |
match qty { | |
Ok(x) => Ok(x * cost_per_item + processing_fee), | |
Err(x) => Err(x) | |
} | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[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().to_string(), | |
"invalid digit found in string" | |
); | |
} | |
} | |
// One way to handle this is using a `match` statement on | |
// `item_quantity.parse::<i32>()` where the cases are `Ok(something)` and | |
// `Err(something)`. This pattern is very common in Rust, though, so there's | |
// a `?` operator that does pretty much what you would make that match statement | |
// do for you! Take a look at this section of the Error Handling chapter: | |
// https://doc.rust-lang.org/stable/book/second-edition/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator | |
// and give it a try! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// option1.rs | |
// This example panics because the second time it calls `pop`, the `vec` | |
// is empty, so `pop` returns `None`, and `unwrap` panics if it's called | |
// on `None`. Handle this in a more graceful way than calling `unwrap`! | |
// Scroll down for hints :) | |
fn main() { | |
let mut list = vec![3]; | |
let last = list.pop().unwrap(); | |
println!("The last item in the list is {:?}", last); | |
let second_to_last = list.pop().unwrap_or(3); | |
println!("The second-to-last item in the list is {:?}", second_to_last); | |
} | |
// Try using a `match` statement where the arms are `Some(thing)` and `None`. | |
// Or set a default value to print out if you get `None` by using the | |
// function `unwrap_or`. | |
// Or use an `if let` statement on the result of `pop()` to both destructure | |
// a `Some` value and only print out something if we have a value! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// result1.rs | |
// Make this test pass! Scroll down for hints :) | |
#[derive(PartialEq,Debug)] | |
struct PositiveNonzeroInteger(u64); | |
#[derive(PartialEq,Debug)] | |
enum CreationError { | |
Negative, | |
Zero, | |
} | |
impl PositiveNonzeroInteger { | |
fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> { | |
if value == 0 { | |
Err(CreationError::Zero) | |
}else if value < 0{ | |
Err(CreationError::Negative) | |
}else{ | |
Ok(PositiveNonzeroInteger(value as u64)) | |
} | |
} | |
} | |
#[test] | |
fn test_creation() { | |
assert!(PositiveNonzeroInteger::new(10).is_ok()); | |
assert_eq!(Err(CreationError::Negative), PositiveNonzeroInteger::new(-10)); | |
assert_eq!(Err(CreationError::Zero), PositiveNonzeroInteger::new(0)); | |
} | |
// `PositiveNonzeroInteger::new` is always creating a new instance and returning an `Ok` result. | |
// It should be doing some checking, returning an `Err` result if those checks fail, and only | |
// returning an `Ok` result if those checks determine that everything is... okay :) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment