And you then invoke the conversion explicitly (e.g. Fahrenheit::from(celsius)) or using the into() method from the Into trait that you get for free whenever From is implemented.
fn main() {
let c = Celsius(0.0);
// You can explicitly use the Fahrenheit::from() to do the conversion
let f = Fahrenheit::from(c);
assert_eq!(f, Fahrenheit(32.0));
// Or you can use the into() method and let type inference figure out which
// conversion to use
let equivalent_celsius: Celsius = f.into();
assert_eq!(equivalent_celsius, c);
}
You can think of the as keyword as a tool for coercing between different primitive types, so bool -> u8, f32 -> u64, *const Foo -> *mut Bar, and so on, and is deliberately not extensible because it'll do the corresponding compiler magic. The Rust Reference has a chapter on type cast expressions if you want to find out more.
impl From<f64> for Celsius {
fn from(value: f64) -> Celsius {
if value < -273.15 {
Celsius(f64::NAN)
} else {
Celsius(value)
}
}
}
However, let c: Celsius = Celsius(-275.0) does not run into the function defined in the From trait. How can I make it similar to Celsius c(-275.0) in C++? Or how can I prevent users from calling let c: Celsius = Celsius(-275.0)?
You should avoid using as conversion actually.
Using into() and try_into().unwrap() is better because they fail conversion instead of providing invalid value.
E.g.:
let a: u32 = 100000;
let b: u16 = a as u16; // Silently corrupts data
let b: u16 = a.into(); // Doesn't compile
let b: u16 = a.try_into().unwrap(); // panics at runtime
let a: u8 = 5;
let b: u32 = a.into(); // OK
let a: u32 = 5;
let b: u8 = a.try_into().unwrap(); // OK