From and Into
Part of the Object Oriented Programming section of Coddy's Rust journey — lesson 57 of 61.
Converting between types is a common task in Rust. The From trait provides a standardized way to define how one type can be created from another. When you implement From, you get the Into trait automatically for free.
To implement From, you define how to construct your type from another type:
struct Meters(f64);
struct Kilometers(f64);
impl From<Kilometers> for Meters {
fn from(km: Kilometers) -> Self {
Meters(km.0 * 1000.0)
}
}
Now you can convert using either the from function or the into method:
let distance = Kilometers(5.0);
// Using From explicitly
let m1 = Meters::from(distance);
// Using Into (works because From is implemented)
let distance = Kilometers(3.0);
let m2: Meters = distance.into();
The into() method requires a type annotation since Rust needs to know what type you're converting to. This pattern is especially useful when you have helper structs that need to be converted into your main types—like converting configuration data into an initialized object, or transforming raw input into a validated structure.
Challenge
EasyLet's build a temperature conversion system using the From trait! You'll create two temperature types—Celsius and Fahrenheit—and implement conversions between them using Rust's standard conversion traits.
You'll organize your code across two files:
temperature.rs: Define two public newtype structs—CelsiusandFahrenheit—both wrapping anf64. Implement theFromtrait to convertCelsiusintoFahrenheitusing the formula:fahrenheit = celsius × 1.8 + 32.0. Also add avaluemethod to each struct that returns the innerf64.main.rs: Bring in your temperature module and demonstrate both conversion approaches. Create aCelsiusvalue from the provided input, then convert it toFahrenheitusingFahrenheit::from(). Create anotherCelsiusvalue and convert it using the.into()method. Print both results.
The conversion formula from Celsius to Fahrenheit is: multiply by 1.8 and add 32. Remember that implementing From<Celsius> for Fahrenheit automatically gives you the Into<Fahrenheit> trait on Celsius for free!
Your output should display both conversions in this format:
From: {celsius1}C = {fahrenheit1}F
Into: {celsius2}C = {fahrenheit2}FFor example, with inputs 0 and 100:
From: 0C = 32F
Into: 100C = 212FAnd with inputs 25 and -40:
From: 25C = 77F
Into: -40C = -40FYou will receive two inputs: the first Celsius value (parse as f64) and the second Celsius value (parse as f64).
Cheat sheet
The From trait provides a standardized way to convert between types. When you implement From, you automatically get the Into trait for free.
To implement From, define how to construct your type from another type:
struct Meters(f64);
struct Kilometers(f64);
impl From<Kilometers> for Meters {
fn from(km: Kilometers) -> Self {
Meters(km.0 * 1000.0)
}
}
You can convert using either the from function or the into method:
let distance = Kilometers(5.0);
// Using From explicitly
let m1 = Meters::from(distance);
// Using Into (requires type annotation)
let distance = Kilometers(3.0);
let m2: Meters = distance.into();
The into() method requires a type annotation so Rust knows what type you're converting to.
Try it yourself
mod temperature;
use temperature::{Celsius, Fahrenheit};
fn main() {
// Read input
let mut input1 = String::new();
std::io::stdin().read_line(&mut input1).expect("Failed to read line");
let celsius1: f64 = input1.trim().parse().expect("Invalid number");
let mut input2 = String::new();
std::io::stdin().read_line(&mut input2).expect("Failed to read line");
let celsius2: f64 = input2.trim().parse().expect("Invalid number");
// TODO: Create a Celsius value from celsius1
// TODO: Convert it to Fahrenheit using Fahrenheit::from()
// TODO: Create another Celsius value from celsius2
// TODO: Convert it to Fahrenheit using .into()
// TODO: Print the results in the format:
// From: {celsius1}C = {fahrenheit1}F
// Into: {celsius2}C = {fahrenheit2}F
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Methods and Behavior
Intro Implementation BlocksThe Self ParameterMutable MethodsAssociated FunctionsMultiple Implementation BlocksMethod ChainingRecap - Rectangle Actions4Project: Virtual Pet
Defining the PetFeeding the Pet7Standard Traits
The Debug TraitThe Display TraitClone and CopyEquality TraitsRecap - Printable Point10Project: Document System
The Draw TraitText Component2Encapsulation and Modules
Modules BasicsThe Public KeywordPrivate FieldsGettersSettersRecap - Secure Locker5Generics
Generic StructsGeneric MethodsMultiple Generic TypesGeneric FunctionsRecap - Coordinate Point8Traits as Bounds
Trait Bounds SyntaxMultiple BoundsThe Where ClauseReturning Types with TraitsRecap - Generic Printer11Design Patterns in Rust
Newtype PatternCompositionThe Drop TraitFrom and IntoRecap - Smart Pointer Mock