diff options
| author | Taylor Yu <tlyu@mit.edu> | 2021-06-24 21:33:41 -0500 |
|---|---|---|
| committer | Taylor Yu <tlyu@mit.edu> | 2021-06-24 21:33:41 -0500 |
| commit | 2dc93caddad43821743e4903d89b355df58d7a49 (patch) | |
| tree | 050edd4010df3358e7a50087ed4aa9b49cca7911 /exercises/conversions/from_str.rs | |
| parent | de6c45ad244528562889138757f3c8c7f089bbec (diff) | |
fix(from_str, try_from_into): custom error types
Remove the use of trait objects as errors from `from_str` and
`try_from_into`; they seem to have caused a lot of confusion in
practice. (Also, it's considered best practice to use custom error
types instead of boxed errors in library code.) Instead, use custom
error enums, and update hints accordingly. Hints also provide
some guidance about converting errors, which could be covered
more completely in a future advanced errors section.
Also move from_str to directly after the similar exercise `from_into`,
for the sake of familiarity when solving.
Diffstat (limited to 'exercises/conversions/from_str.rs')
| -rw-r--r-- | exercises/conversions/from_str.rs | 56 |
1 files changed, 43 insertions, 13 deletions
diff --git a/exercises/conversions/from_str.rs b/exercises/conversions/from_str.rs index 4beebac..6e9e699 100644 --- a/exercises/conversions/from_str.rs +++ b/exercises/conversions/from_str.rs @@ -1,16 +1,31 @@ -// This does practically the same thing that TryFrom<&str> does. +// from_str.rs +// This is similar to from_into.rs, but this time we'll implement `FromStr` +// and return errors instead of falling back to a default value. // Additionally, upon implementing FromStr, you can use the `parse` method // on strings to generate an object of the implementor type. // You can read more about it at https://doc.rust-lang.org/std/str/trait.FromStr.html -use std::error; +use std::num::ParseIntError; use std::str::FromStr; -#[derive(Debug)] +#[derive(Debug, PartialEq)] struct Person { name: String, age: usize, } +// We will use this error type for the `FromStr` implementation. +#[derive(Debug, PartialEq)] +enum ParsePersonError { + // Empty input string + Empty, + // Incorrect number of fields + BadLen, + // Empty name field + NoName, + // Wrapped error from parse::<usize>() + ParseInt(ParseIntError), +} + // I AM NOT DONE // Steps: @@ -24,7 +39,7 @@ struct Person { // If everything goes well, then return a Result of a Person object impl FromStr for Person { - type Err = Box<dyn error::Error>; + type Err = ParsePersonError; fn from_str(s: &str) -> Result<Person, Self::Err> { } } @@ -40,7 +55,7 @@ mod tests { #[test] fn empty_input() { - assert!("".parse::<Person>().is_err()); + assert_eq!("".parse::<Person>(), Err(ParsePersonError::Empty)); } #[test] fn good_input() { @@ -52,41 +67,56 @@ mod tests { } #[test] fn missing_age() { - assert!("John,".parse::<Person>().is_err()); + assert!(matches!( + "John,".parse::<Person>(), + Err(ParsePersonError::ParseInt(_)) + )); } #[test] fn invalid_age() { - assert!("John,twenty".parse::<Person>().is_err()); + assert!(matches!( + "John,twenty".parse::<Person>(), + Err(ParsePersonError::ParseInt(_)) + )); } #[test] fn missing_comma_and_age() { - assert!("John".parse::<Person>().is_err()); + assert_eq!("John".parse::<Person>(), Err(ParsePersonError::BadLen)); } #[test] fn missing_name() { - assert!(",1".parse::<Person>().is_err()); + assert_eq!(",1".parse::<Person>(), Err(ParsePersonError::NoName)); } #[test] fn missing_name_and_age() { - assert!(",".parse::<Person>().is_err()); + assert!(matches!( + ",".parse::<Person>(), + Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_)) + )); } #[test] fn missing_name_and_invalid_age() { - assert!(",one".parse::<Person>().is_err()); + assert!(matches!( + ",one".parse::<Person>(), + Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_)) + )); } #[test] fn trailing_comma() { - assert!("John,32,".parse::<Person>().is_err()); + assert_eq!("John,32,".parse::<Person>(), Err(ParsePersonError::BadLen)); } #[test] fn trailing_comma_and_some_string() { - assert!("John,32,man".parse::<Person>().is_err()); + assert_eq!( + "John,32,man".parse::<Person>(), + Err(ParsePersonError::BadLen) + ); } } |
