From / Into / TryFrom / TryInto Traits
Rust's type conversion traits — From, Into, TryFrom, and TryInto — standardize conversions between types. Implementing From automatically provides Into as well.
Syntax
use std::convert::TryFrom;
// Implementing the From trait.
struct Wrapper(i32);
impl From<i32> for Wrapper {
fn from(val: i32) -> Self {
Wrapper(val)
}
}
// Implementing From automatically enables Into as well.
let w: Wrapper = Wrapper::from(42); // Using From.
let w: Wrapper = 42.into(); // Using Into (type annotation specifies the target type).
// TryFrom: a fallible conversion that returns a Result.
impl TryFrom<i32> for Wrapper {
type Error = String;
fn try_from(val: i32) -> Result<Self, Self::Error> {
if val >= 0 {
Ok(Wrapper(val))
} else {
Err(format!("Negative values are not accepted: {}", val))
}
}
}
Conversion Traits
| Trait | Description |
|---|---|
| From<T> | Converts from another type T into the implementing type (infallible conversion). |
| Into<U> | Converts the implementing type into another type U (automatically implemented when From<Self> for U is implemented). |
| TryFrom<T> | Attempts to convert from another type T into the implementing type, returning Result<Self, Error>. |
| TryInto<U> | Attempts to convert the implementing type into another type U (the counterpart of TryFrom). |
| AsRef<T> | Provides a conversion from the implementing type to &T (a zero-cost reference conversion). |
| AsMut<T> | Provides a conversion from the implementing type to &mut T. |
Sample Code
use std::convert::TryFrom;
#[derive(Debug)]
struct Celsius(f64);
#[derive(Debug)]
struct Fahrenheit(f64);
// Converting from Fahrenheit to Celsius.
impl From<Fahrenheit> for Celsius {
fn from(f: Fahrenheit) -> Self {
Celsius((f.0 - 32.0) * 5.0 / 9.0)
}
}
// Converting from Celsius to Fahrenheit.
impl From<Celsius> for Fahrenheit {
fn from(c: Celsius) -> Self {
Fahrenheit(c.0 * 9.0 / 5.0 + 32.0)
}
}
// A newtype pattern with a constrained value range.
#[derive(Debug)]
struct Percentage(f64);
impl TryFrom<f64> for Percentage {
type Error = String;
fn try_from(value: f64) -> Result<Self, Self::Error> {
if (0.0..=100.0).contains(&value) {
Ok(Percentage(value))
} else {
Err(format!("Percentage must be between 0 and 100. Got: {}", value))
}
}
}
fn main() {
// Using From / Into.
let boiling_f = Fahrenheit(212.0);
let boiling_c = Celsius::from(boiling_f);
println!("212°F = {:.1}°C", boiling_c.0);
let freezing_c = Celsius(0.0);
let freezing_f: Fahrenheit = freezing_c.into(); // Using Into.
println!("0°C = {:.1}°F", freezing_f.0);
// Examples of From / Into from the standard library.
let s = String::from("hello"); // From<&str> for String
let s2: String = "world".into(); // Into<String> for &str
println!("{}, {}", s, s2);
let n: i64 = 42_i32.into(); // Safe conversion from i32 to i64.
println!("i32 -> i64: {}", n);
// Using TryFrom.
let good = Percentage::try_from(75.0);
let bad = Percentage::try_from(150.0);
println!("75.0 -> {:?}", good); // Ok(Percentage(75.0))
println!("150.0 -> {:?}", bad); // Err(...)
// TryInto works the same way (requires use std::convert::TryInto).
use std::convert::TryInto;
let result: Result<Percentage, _> = 50.0_f64.try_into();
println!("50.0 try_into: {:?}", result);
// From/Into example with strings.
let num: i32 = 42;
let s = num.to_string(); // ToString is auto-implemented via Display
let back: i32 = s.parse().unwrap();
println!("i32 -> String -> i32: {}", back);
}
Notes
Implementing From automatically provides Into. This is known as Rust's "From/Into duality" — you only need to implement From, and Into is derived for free.
When writing function parameters, accepting Into frees callers from having to convert manually. For example, fn new(name: impl Into<String>) accepts both &str and String, making the function more flexible.
For the basics of trait definitions, see trait / impl Trait for Type.
If you find any errors or copyright issues, please contact us.