diff --git a/exercises/23_conversions/conversions2.rs b/exercises/23_conversions/conversions2.rs index f6df67f2..491b8073 100644 --- a/exercises/23_conversions/conversions2.rs +++ b/exercises/23_conversions/conversions2.rs @@ -3,50 +3,52 @@ // You can read more about it in the documentation: // https://doc.rust-lang.org/std/convert/trait.From.html // -// Frank the fairy would like to buy some truffles from Grace the gnome, a -// world-renowned chocolatier. The truffles are priced in GnomeCoin though, and -// Frank only has FairyCredit. Help Frank by providing a `From` implementation -// to convert his FairyCredit to GnomeCoin. At the current exchange rate, one -// FairyCredit is valued at 100 GnomeCoin. +// Representing units of measurements with separate types is a common practice. +// It avoids accidentally mixing up values of different units of measurement. -#[derive(Debug)] -struct FairyCredit(u32); +struct Celsius(f64); -#[derive(Debug, PartialEq)] -struct GnomeCoin(u64); +struct Fahrenheit(f64); -impl From for GnomeCoin { - // TODO: implement From for GnomeCoin +impl From for Fahrenheit { + // TODO: Convert Celsius to Fahrenheit. Don't worry about floating-point + // precision. The formula is: F = C * 1.8 + 32 } -// Note that we shouldn't provide the opposite conversion: from GnomeCoin to -// FairyCredits. That's because less than 100 GnomeCoins cannot be represented -// as FairyCredits, which would make the conversion lossy. The `From` trait is -// only appropriate for infallible and lossless conversions. +impl From for Celsius { + // TODO: Convert Fahrenheit to Celsius. +} fn main() { - // Use the `from` function. - let g1 = GnomeCoin::from(FairyCredit(12)); - println!("{g1:?}"); - - // Since `From` is implemented for GnomeCoin, we are able to use `Into`. - let g2: GnomeCoin = FairyCredit(9).into(); - println!("{g2:?}"); + // You can optionally experiment here. } #[cfg(test)] mod tests { use super::*; + const CASES: [(f64, f64); 6] = [ + (-50.0, -58.0), + (0.0, 32.0), + (20.0, 68.0), + (100.0, 212.0), + (400.0, 752.0), + (1000.0, 1832.0), + ]; + #[test] - fn test_from() { - let g = GnomeCoin::from(FairyCredit(12)); - assert_eq!(g, GnomeCoin(1200)); + fn celsius_to_fahrenheit() { + for (celsius, fahrenheit) in CASES { + let Fahrenheit(actual) = Celsius(celsius).into(); + assert_eq!(actual.round(), fahrenheit); + } } #[test] - fn test_into() { - let g: GnomeCoin = FairyCredit(9).into(); - assert_eq!(g, GnomeCoin(900)); + fn fahrenheit_to_celsius() { + for (celsius, fahrenheit) in CASES { + let Celsius(actual) = Fahrenheit(fahrenheit).into(); + assert_eq!(actual.round(), celsius); + } } } diff --git a/rustlings-macros/info.toml b/rustlings-macros/info.toml index 054da99b..08f83e5f 100644 --- a/rustlings-macros/info.toml +++ b/rustlings-macros/info.toml @@ -1171,9 +1171,8 @@ Use the `as` operator to cast one of the operands in the last line of the name = "conversions2" dir = "23_conversions" hint = """ -Implement From for GnomeCoin. Check the documentation of `From` to -learn about its required items: -https://doc.rust-lang.org/std/convert/trait.From.html""" +For the conversion from Fahrenheit to Celsius, you have to determine the formula +yourself. Don't forget the order of operations!""" [[exercises]] name = "conversions3" diff --git a/solutions/23_conversions/conversions2.rs b/solutions/23_conversions/conversions2.rs index b8b2372e..c8580f6b 100644 --- a/solutions/23_conversions/conversions2.rs +++ b/solutions/23_conversions/conversions2.rs @@ -3,52 +3,55 @@ // You can read more about it in the documentation: // https://doc.rust-lang.org/std/convert/trait.From.html // -// Frank the fairy would like to buy some truffles from Grace the gnome, a -// world-renowned chocolatier. The truffles are priced in GnomeCoin though, and -// Frank only has FairyCredit. Help Frank by providing a `From` implementation -// to convert his FairyCredit to GnomeCoin. At the current exchange rate, one -// FairyCredit is valued at 100 GnomeCoin. +// Representing units of measurements with separate types is a common practice. +// It avoids accidentally mixing up values of different units of measurement. -#[derive(Debug)] -struct FairyCredit(u32); +struct Celsius(f64); -#[derive(Debug, PartialEq)] -struct GnomeCoin(u64); +struct Fahrenheit(f64); -impl From for GnomeCoin { - fn from(value: FairyCredit) -> Self { - Self(value.0 as u64 * 100) +impl From for Fahrenheit { + fn from(Celsius(celsius): Celsius) -> Self { + Fahrenheit(celsius * 1.8 + 32.0) } } -// Note that we shouldn't provide the opposite conversion: from GnomeCoin to -// FairyCredits. That's because less than 100 GnomeCoins cannot be represented -// as FairyCredits, which would make the conversion lossy. The `From` trait is -// only appropriate for infallible and lossless conversions. +impl From for Celsius { + fn from(Fahrenheit(fahrenheit): Fahrenheit) -> Self { + Celsius((fahrenheit - 32.0) / 1.8) + } +} fn main() { - // Use the `from` function. - let g1 = GnomeCoin::from(FairyCredit(12)); - println!("{g1:?}"); - - // Since `From` is implemented for GnomeCoin, we are able to use `Into`. - let g2: GnomeCoin = FairyCredit(9).into(); - println!("{g2:?}"); + // You can optionally experiment here. } #[cfg(test)] mod tests { use super::*; + const CASES: [(f64, f64); 6] = [ + (-50.0, -58.0), + (0.0, 32.0), + (20.0, 68.0), + (100.0, 212.0), + (400.0, 752.0), + (1000.0, 1832.0), + ]; + #[test] - fn test_from() { - let g = GnomeCoin::from(FairyCredit(12)); - assert_eq!(g, GnomeCoin(1200)); + fn celsius_to_fahrenheit() { + for (celsius, fahrenheit) in CASES { + let Fahrenheit(actual) = Celsius(celsius).into(); + assert_eq!(actual.round(), fahrenheit); + } } #[test] - fn test_into() { - let g: GnomeCoin = FairyCredit(9).into(); - assert_eq!(g, GnomeCoin(900)); + fn fahrenheit_to_celsius() { + for (celsius, fahrenheit) in CASES { + let Celsius(actual) = Fahrenheit(fahrenheit).into(); + assert_eq!(actual.round(), celsius); + } } }