from_str.rs (3090B)
1 // This is similar to the previous `from_into` exercise. But this time, we'll 2 // implement `FromStr` and return errors instead of falling back to a default 3 // value. Additionally, upon implementing `FromStr`, you can use the `parse` 4 // method on strings to generate an object of the implementor type. You can read 5 // more about it in the documentation: 6 // https://doc.rust-lang.org/std/str/trait.FromStr.html 7 8 use std::num::ParseIntError; 9 use std::str::FromStr; 10 11 #[derive(Debug, PartialEq)] 12 struct Person { 13 name: String, 14 age: u8, 15 } 16 17 // We will use this error type for the `FromStr` implementation. 18 #[derive(Debug, PartialEq)] 19 enum ParsePersonError { 20 // Incorrect number of fields 21 BadLen, 22 // Empty name field 23 NoName, 24 // Wrapped error from parse::<u8>() 25 ParseInt(ParseIntError), 26 } 27 28 // TODO: Complete this `FromStr` implementation to be able to parse a `Person` 29 // out of a string in the form of "Mark,20". 30 // Note that you'll need to parse the age component into a `u8` with something 31 // like `"4".parse::<u8>()`. 32 // 33 // Steps: 34 // 1. Split the given string on the commas present in it. 35 // 2. If the split operation returns less or more than 2 elements, return the 36 // error `ParsePersonError::BadLen`. 37 // 3. Use the first element from the split operation as the name. 38 // 4. If the name is empty, return the error `ParsePersonError::NoName`. 39 // 5. Parse the second element from the split operation into a `u8` as the age. 40 // 6. If parsing the age fails, return the error `ParsePersonError::ParseInt`. 41 impl FromStr for Person { 42 type Err = ParsePersonError; 43 44 fn from_str(s: &str) -> Result<Self, Self::Err> {} 45 } 46 47 fn main() { 48 let p = "Mark,20".parse::<Person>(); 49 println!("{p:?}"); 50 } 51 52 #[cfg(test)] 53 mod tests { 54 use super::*; 55 use ParsePersonError::*; 56 57 #[test] 58 fn empty_input() { 59 assert_eq!("".parse::<Person>(), Err(BadLen)); 60 } 61 62 #[test] 63 fn good_input() { 64 let p = "John,32".parse::<Person>(); 65 assert!(p.is_ok()); 66 let p = p.unwrap(); 67 assert_eq!(p.name, "John"); 68 assert_eq!(p.age, 32); 69 } 70 71 #[test] 72 fn missing_age() { 73 assert!(matches!("John,".parse::<Person>(), Err(ParseInt(_)))); 74 } 75 76 #[test] 77 fn invalid_age() { 78 assert!(matches!("John,twenty".parse::<Person>(), Err(ParseInt(_)))); 79 } 80 81 #[test] 82 fn missing_comma_and_age() { 83 assert_eq!("John".parse::<Person>(), Err(BadLen)); 84 } 85 86 #[test] 87 fn missing_name() { 88 assert_eq!(",1".parse::<Person>(), Err(NoName)); 89 } 90 91 #[test] 92 fn missing_name_and_age() { 93 assert!(matches!(",".parse::<Person>(), Err(NoName | ParseInt(_)))); 94 } 95 96 #[test] 97 fn missing_name_and_invalid_age() { 98 assert!(matches!( 99 ",one".parse::<Person>(), 100 Err(NoName | ParseInt(_)), 101 )); 102 } 103 104 #[test] 105 fn trailing_comma() { 106 assert_eq!("John,32,".parse::<Person>(), Err(BadLen)); 107 } 108 109 #[test] 110 fn trailing_comma_and_some_string() { 111 assert_eq!("John,32,man".parse::<Person>(), Err(BadLen)); 112 } 113 }