What is “Conversion” in Rust?
Why Rust Uses Traits for Conversion
Core Conversion Traits (Big Picture)
From Trait (Guaranteed Conversion)
Into Trait (Reverse Direction)
TryFrom and TryInto (Fallible Conversion)
String Conversions (ToString and FromStr)
Conversion Safety Philosophy (Very Important)
Why Rust Conversion Design Is Powerful
Simple Real-World Analogy
Summary
From and Into — 5 unique examples
TryFrom and TryInto — 5 unique examples
To and from Strings — 5 unique examples
What is “Conversion” in Rust?
Conversion in Rust means changing one type into another type in a controlled, safe way.
Rust is a strongly typed language, so it does not allow automatic or unsafe type changes like some other languages.
Instead, Rust uses traits to define how conversions should happen.
Why Rust Uses Traits for Conversion
Rust’s goals:
Safety (no unexpected data loss)
Clarity (you always know when a conversion happens)
Explicitness (no hidden magic)
So conversions are implemented using standard traits such as:
From
Into
TryFrom
TryInto
ToString
FromStr
Each trait answers a specific question:
Is this conversion always safe, or can it fail?
Core Conversion Traits (Big Picture)
From Trait (Guaranteed Conversion)
Theory
From defines how to create type A from type B
It must never fail
If a conversion can fail → do NOT use From
Key Rule
If you implement:
From<B> for A
Rust automatically gives you:
Into<A> for B
This is why From and Into are linked.
Mental Model
“If Rust allows From, the conversion is always valid.”
Into Trait (Reverse Direction)
Theory
Into is just the consumer side of From
You almost never implement Into manually
Rust derives it for you when From exists
Why Into Exists
It helps write generic code where the exact input type is flexible.
TryFrom and TryInto (Fallible Conversion)
Theory
Some conversions can fail, for example:
i64 → u8
String → number
Parsing user input
For these, Rust uses:
TryFrom
TryInto
These traits:
Return Result
Force you to handle failure explicitly
Mental Model
“If data can be invalid or overflow → use TryFrom.”
String Conversions (ToString and FromStr)
ToString
Converts any displayable type into String
Implemented automatically if Display is implemented
FromStr
Parses a String into a value
Can fail → returns Result
This is commonly used when reading input or parsing config values.
Conversion Safety Philosophy (Very Important)
Rust classifies conversions into two categories:
Infallible (Safe)
Use From / Into
Guaranteed correctness
No data loss
Fallible (Unsafe / Risky)
Use TryFrom / TryInto
Forces error handling
Prevents silent bugs
Rust never allows silent failure.
Why Rust Conversion Design Is Powerful
Eliminates runtime surprises
Makes APIs self-documenting
Encourages clean error handling
Works seamlessly with generics
Zero-cost abstractions (no performance penalty)
Simple Real-World Analogy
Think of conversion like currency exchange:
From → exchanging ₹100 to ₹100 (no loss, always valid)
TryFrom → exchanging ₹ to foreign currency (rate may not exist)
Rust forces you to check the exchange rate before proceeding.
Summary
Rust uses traits, not casts, for conversion
From / Into → always safe
TryFrom / TryInto → may fail
ToString / FromStr → text conversion
Safety + clarity > convenience
From and Into — 5 unique examples
From<&str> for Person (auto enables Into<Person>)
#[derive(Debug)]
struct Person {
name: String,
}
impl From<&str> for Person {
fn from(s: &str) -> Self {
Person { name: s.to_string() }
}
}
fn main() {
let p1 = Person::from("Ashwani");
let p2: Person = "Rahul".into();
println!("{:?}", p1);
println!("{:?}", p2);
}
Output
Person { name: "Ashwani" }
Person { name: "Rahul" }
2) From for Temperature
#[derive(Debug)]
struct Temperature(i32);
impl From<i32> for Temperature {
fn from(v: i32) -> Self {
Temperature(v)
}
}
fn main() {
let t1 = Temperature::from(30);
let t2: Temperature = 45.into();
println!("{:?}", t1);
println!("{:?}", t2);
}
Output
Temperature(30)
Temperature(45)
3) Convert between tuple and struct using From
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
impl From<(i32, i32)> for Point {
fn from(t: (i32, i32)) -> Self {
Point { x: t.0, y: t.1 }
}
}
fn main() {
let p: Point = (10, 20).into();
println!("{:?}", p);
}
Output
Point { x: 10, y: 20 }
4) From for i32 using standard conversion pattern (custom type)
#[derive(Debug)]
struct FlagNum(i32);
impl From<bool> for FlagNum {
fn from(b: bool) -> Self {
FlagNum(if b { 1 } else { 0 })
}
}
fn main() {
let a: FlagNum = true.into();
let b: FlagNum = false.into();
println!("{:?}", a);
println!("{:?}", b);
}
Output
FlagNum(1)
FlagNum(0)
5) Into in function argument (accept many input types)
fn greet(name: impl Into<String>) {
let n = name.into();
println!("Hello, {}", n);
}
fn main() {
greet("Ashwani"); // &str
greet(String::from("Sonia")); // String
}
Output
Hello, Ashwani
Hello, Sonia
TryFrom and TryInto — 5 unique examples
TryFrom<i32> with range validation
use std::convert::TryFrom;
#[derive(Debug)]
struct Age(u8);
impl TryFrom<i32> for Age {
type Error = String;
fn try_from(v: i32) -> Result<Self, Self::Error> {
if (0..=120).contains(&v) {
Ok(Age(v as u8))
} else {
Err(format!("Invalid age: {}", v))
}
}
}
fn main() {
println!("{:?}", Age::try_from(27));
println!("{:?}", Age::try_from(200));
}
Output
Ok(Age(27))
Err("Invalid age: 200")
2) TryInto usage (same converter, different syntax)
use std::convert::TryInto;
#[derive(Debug)]
struct Percent(u8);
impl std::convert::TryFrom<i32> for Percent {
type Error = String;
fn try_from(v: i32) -> Result<Self, Self::Error> {
if (0..=100).contains(&v) {
Ok(Percent(v as u8))
} else {
Err(format!("Not a percent: {}", v))
}
}
}
fn main() {
let a: Result<Percent, _> = 85.try_into();
let b: Result<Percent, _> = 180.try_into();
println!("{:?}", a);
println!("{:?}", b);
}
Output
Ok(Percent(85))
Err("Not a percent: 180")
3) TryFrom<&str> parse integer safely
use std::convert::TryFrom;
#[derive(Debug)]
struct OrderId(u32);
impl TryFrom<&str> for OrderId {
type Error = String;
fn try_from(s: &str) -> Result<Self, Self::Error> {
let n: u32 = s.parse().map_err(|_| "Invalid number".to_string())?;
Ok(OrderId(n))
}
}
fn main() {
println!("{:?}", OrderId::try_from("12345"));
println!("{:?}", OrderId::try_from("ABCD"));
}
Output
Ok(OrderId(12345))
Err("Invalid number")
4) TryFrom only allow digits
use std::convert::TryFrom;
#[derive(Debug)]
struct Digit(u8);
impl TryFrom<char> for Digit {
type Error = String;
fn try_from(c: char) -> Result<Self, Self::Error> {
if c.is_ascii_digit() {
Ok(Digit(c.to_digit(10).unwrap() as u8))
} else {
Err(format!("Not a digit: {}", c))
}
}
}
fn main() {
println!("{:?}", Digit::try_from('7'));
println!("{:?}", Digit::try_from('A'));
}
Output
Ok(Digit(7))
Err("Not a digit: A")
5) TryFrom<(i32,i32)> for Point with bounds check
use std::convert::TryFrom;
#[derive(Debug)]
struct Point2D { x: i32, y: i32 }
impl TryFrom<(i32, i32)> for Point2D {
type Error = String;
fn try_from(t: (i32, i32)) -> Result<Self, Self::Error> {
let (x, y) = t;
if (-100..=100).contains(&x) && (-100..=100).contains(&y) {
Ok(Point2D { x, y })
} else {
Err("Point out of allowed range".to_string())
}
}
}
fn main() {
println!("{:?}", Point2D::try_from((10, -20)));
println!("{:?}", Point2D::try_from((500, 1)));
}
Output
Ok(Point2D { x: 10, y: -20 })
Err("Point out of allowed range")
To and from Strings — 5 unique examples
to_string() (any type implementing Display)
fn main() {
let n = 99;
let s = n.to_string();
println!("{}", s);
}
Output
99
2) String::from and "literal".to_string()
fn main() {
let a = String::from("Hello");
let b = "World".to_string();
println!("{} {}", a, b);
}
Output
Hello World
3) &str ↔ String using .as_str() and borrowing
fn main() {
let s = String::from("Rust");
let slice: &str = s.as_str();
println!("String: {}", s);
println!("&str: {}", slice);
}
Output
String: Rust
&str: Rust
4) Parse String to number (parse)
fn main() {
let text = "120";
let num: i32 = text.parse().unwrap();
println!("num = {}", num);
}
Output
num = 120
5) Build String using format! + push / push_str
fn main() {
let mut s = String::new();
s.push('A');
s.push_str("shwani");
let final_str = format!("Hello, {}!", s);
println!("{}", final_str);
}
Output
Hello, Ashwani!
Top comments (0)