Rust's conversion traits make APIs predictable. The main question is whether a conversion takes ownership, can fail, or only borrows a value.
From and Into: infallible owned conversions
Use From when every valid source value can become the destination. Implement From; Rust provides the matching Into implementation automatically.
struct UserId(u64);
impl From<u64> for UserId {
fn from(value: u64) -> Self {
Self(value)
}
}
let direct = UserId::from(42);
let inferred: UserId = 42.into();
These conversions consume the input. Do not use From when conversion can fail or discard important information.
TryFrom and TryInto: fallible owned conversions
Use TryFrom when validation is required. As with From, implementing the destination-side trait gives you TryInto for free.
use std::convert::TryFrom;
struct Percentage(u8);
impl TryFrom<u8> for Percentage {
type Error = &'static str;
fn try_from(value: u8) -> Result<Self, Self::Error> {
(value <= 100)
.then_some(Self(value))
.ok_or("percentage must be 0..=100")
}
}
let valid = Percentage::try_from(80).expect("valid percentage");
let invalid: Result<Percentage, _> = 120_u8.try_into();
AsRef: cheap shared borrowing
AsRef<T> exposes a shared reference without taking ownership. It is useful for flexible function parameters:
use std::path::Path;
fn extension(path: impl AsRef<Path>) -> Option<String> {
path.as_ref()
.extension()
.map(|ext| ext.to_string_lossy().into_owned())
}
assert_eq!(extension("notes.md").as_deref(), Some("md"));
This accepts values such as &str, String, &Path, and PathBuf while the function works with &Path.
AsMut: cheap mutable borrowing
AsMut<T> is the mutable counterpart to AsRef:
fn clear(mut bytes: impl AsMut<[u8]>) {
bytes.as_mut().fill(0);
}
let mut buffer = vec![1, 2, 3];
clear(&mut buffer);
assert_eq!(buffer, [0, 0, 0]);
Quick chooser
| Need | Trait to implement or accept |
|---|---|
| Consume a value; conversion cannot fail | From / Into |
| Consume a value; conversion can fail | TryFrom / TryInto |
| Borrow a shared view cheaply | AsRef |
| Borrow a mutable view cheaply | AsMut |
Prefer implementing From or TryFrom; their Into counterparts follow automatically. Use AsRef and AsMut at API boundaries when callers may naturally hold several compatible types.
This overview was inspired by Oliver Jumpertz's You Should Really Know These Traits in Rust. The standard library conversion module documents the complete contracts.