|
2 | 2 | // implemented, an implementation of `Into` is automatically provided. |
3 | 3 | // You can read more about it in the documentation: |
4 | 4 | // https://doc.rust-lang.org/std/convert/trait.From.html |
| 5 | +// |
| 6 | +// Frank the fairy would like to buy some truffles from Grace the gnome, a |
| 7 | +// world-renowned chocolatier. The truffles are priced in GnomeCoin though, and |
| 8 | +// Frank only has FairyCredit. Help Frank by providing a `From` implementation |
| 9 | +// to convert his FairyCredit to GnomeCoin. At the current exchange rate, one |
| 10 | +// FairyCredit is valued at 100 GnomeCoin. |
5 | 11 |
|
6 | 12 | #[derive(Debug)] |
7 | | -struct Person { |
8 | | - name: String, |
9 | | - age: u8, |
10 | | -} |
| 13 | +struct FairyCredit(u32); |
11 | 14 |
|
12 | | -// We implement the Default trait to use it as a fallback when the provided |
13 | | -// string is not convertible into a `Person` object. |
14 | | -impl Default for Person { |
15 | | - fn default() -> Self { |
16 | | - Self { |
17 | | - name: String::from("John"), |
18 | | - age: 30, |
19 | | - } |
20 | | - } |
21 | | -} |
| 15 | +#[derive(Debug, PartialEq)] |
| 16 | +struct GnomeCoin(u64); |
22 | 17 |
|
23 | | -// TODO: Complete this `From` implementation to be able to parse a `Person` |
24 | | -// out of a string in the form of "Mark,20". |
25 | | -// Note that you'll need to parse the age component into a `u8` with something |
26 | | -// like `"4".parse::<u8>()`. |
27 | | -// |
28 | | -// Steps: |
29 | | -// 1. Split the given string on the commas present in it. |
30 | | -// 2. If the split operation returns less or more than 2 elements, return the |
31 | | -// default of `Person`. |
32 | | -// 3. Use the first element from the split operation as the name. |
33 | | -// 4. If the name is empty, return the default of `Person`. |
34 | | -// 5. Parse the second element from the split operation into a `u8` as the age. |
35 | | -// 6. If parsing the age fails, return the default of `Person`. |
36 | | -impl From<&str> for Person { |
37 | | - fn from(s: &str) -> Self {} |
| 18 | +impl From<FairyCredit> for GnomeCoin { |
| 19 | + // TODO: implement From<FairyCredit> for GnomeCoin |
38 | 20 | } |
39 | 21 |
|
| 22 | +// Note that we shouldn't provide the opposite conversion: from GnomeCoin to |
| 23 | +// FairyCredits. That's because less than 100 GnomeCoins cannot be represented |
| 24 | +// as FairyCredits, which would make the conversion lossy. The `From` trait is |
| 25 | +// only appropriate for infallible and lossless conversions. |
| 26 | + |
40 | 27 | fn main() { |
41 | 28 | // Use the `from` function. |
42 | | - let p1 = Person::from("Mark,20"); |
43 | | - println!("{p1:?}"); |
| 29 | + let g1 = GnomeCoin::from(FairyCredit(12)); |
| 30 | + println!("{g1:?}"); |
44 | 31 |
|
45 | | - // Since `From` is implemented for Person, we are able to use `Into`. |
46 | | - let p2: Person = "Gerald,70".into(); |
47 | | - println!("{p2:?}"); |
| 32 | + // Since `From` is implemented for GnomeCoin, we are able to use `Into`. |
| 33 | + let g2: GnomeCoin = FairyCredit(9).into(); |
| 34 | + println!("{g2:?}"); |
48 | 35 | } |
49 | 36 |
|
50 | 37 | #[cfg(test)] |
51 | 38 | mod tests { |
52 | 39 | use super::*; |
53 | 40 |
|
54 | 41 | #[test] |
55 | | - fn test_default() { |
56 | | - let dp = Person::default(); |
57 | | - assert_eq!(dp.name, "John"); |
58 | | - assert_eq!(dp.age, 30); |
59 | | - } |
60 | | - |
61 | | - #[test] |
62 | | - fn test_bad_convert() { |
63 | | - let p = Person::from(""); |
64 | | - assert_eq!(p.name, "John"); |
65 | | - assert_eq!(p.age, 30); |
66 | | - } |
67 | | - |
68 | | - #[test] |
69 | | - fn test_good_convert() { |
70 | | - let p = Person::from("Mark,20"); |
71 | | - assert_eq!(p.name, "Mark"); |
72 | | - assert_eq!(p.age, 20); |
73 | | - } |
74 | | - |
75 | | - #[test] |
76 | | - fn test_bad_age() { |
77 | | - let p = Person::from("Mark,twenty"); |
78 | | - assert_eq!(p.name, "John"); |
79 | | - assert_eq!(p.age, 30); |
80 | | - } |
81 | | - |
82 | | - #[test] |
83 | | - fn test_missing_comma_and_age() { |
84 | | - let p: Person = Person::from("Mark"); |
85 | | - assert_eq!(p.name, "John"); |
86 | | - assert_eq!(p.age, 30); |
87 | | - } |
88 | | - |
89 | | - #[test] |
90 | | - fn test_missing_age() { |
91 | | - let p: Person = Person::from("Mark,"); |
92 | | - assert_eq!(p.name, "John"); |
93 | | - assert_eq!(p.age, 30); |
94 | | - } |
95 | | - |
96 | | - #[test] |
97 | | - fn test_missing_name() { |
98 | | - let p: Person = Person::from(",1"); |
99 | | - assert_eq!(p.name, "John"); |
100 | | - assert_eq!(p.age, 30); |
101 | | - } |
102 | | - |
103 | | - #[test] |
104 | | - fn test_missing_name_and_age() { |
105 | | - let p: Person = Person::from(","); |
106 | | - assert_eq!(p.name, "John"); |
107 | | - assert_eq!(p.age, 30); |
108 | | - } |
109 | | - |
110 | | - #[test] |
111 | | - fn test_missing_name_and_invalid_age() { |
112 | | - let p: Person = Person::from(",one"); |
113 | | - assert_eq!(p.name, "John"); |
114 | | - assert_eq!(p.age, 30); |
115 | | - } |
116 | | - |
117 | | - #[test] |
118 | | - fn test_trailing_comma() { |
119 | | - let p: Person = Person::from("Mike,32,"); |
120 | | - assert_eq!(p.name, "John"); |
121 | | - assert_eq!(p.age, 30); |
| 42 | + fn test_from() { |
| 43 | + let g = GnomeCoin::from(FairyCredit(12)); |
| 44 | + assert_eq!(g, GnomeCoin(1200)); |
122 | 45 | } |
123 | 46 |
|
124 | 47 | #[test] |
125 | | - fn test_trailing_comma_and_some_string() { |
126 | | - let p: Person = Person::from("Mike,32,dog"); |
127 | | - assert_eq!(p.name, "John"); |
128 | | - assert_eq!(p.age, 30); |
| 48 | + fn test_into() { |
| 49 | + let g: GnomeCoin = FairyCredit(9).into(); |
| 50 | + assert_eq!(g, GnomeCoin(900)); |
129 | 51 | } |
130 | 52 | } |
0 commit comments