Rust From/Into:把类型转换写成 trait
更新时间:2026-09-20。Rust 没有隐式构造转换,凡「一个类型怎么变成另一个类型」都由标准库的转换 trait 表达,编译器还会自动做一半推导。trait 基础见 trait 与泛型约束,错误转换的应用见 Result 与 ?。
一、From 与 Into 是同一件事的两面
标准库有个覆盖实现(blanket impl):只要你实现了 From<A> for B,就自动免费得到 Into<B> for A。所以约定俗成只写 From,Into 自动来。
rust
let s = String::from("hello"); // From<&str> for String
let t: String = "hello".into(); // 同一个转换,换个调用方向
assert_eq!(s, t);
// 给自己的类型实现 From
struct Years(u32);
impl From<u32> for Years {
fn from(v: u32) -> Self { Years(v) }
}
let y: Years = 18.into(); // Into 自动可用
let z = Years::from(18); // 同一个东西From/Into 语义是不会失败、通常无损的转换;它还被 ? 复用:错误经 From 自动提升为函数声明的错误类型。
二、TryFrom/TryInto:可能失败的转换
整数收窄、字符串转数字等可能越界/非法的转换返回 Result:
rust
use std::convert::TryFrom;
let big: i64 = 500;
let small: Result<u8, _> = u8::try_from(big); // 500 超出 u8 -> Err
assert!(small.is_err());
let n: i32 = "42".parse().unwrap(); // 等价走 FromStr三、四类转换怎么选
| 转换 | trait/写法 | 失败? | 典型 |
|---|---|---|---|
| 无损、必成功 | From/Into | 否 | &str → String、i32 → i64 |
| 可能失败/收窄 | TryFrom/TryInto | 返回 Result | i64 → u8、值转枚举 |
| 字符串 → 类型 | FromStr / .parse::<T>() | Result | "42" → i32 |
| 转成字符串 | ToString(实现 Display 即有)/to_string() | 否 | 数字 → String |
| 原始类型间强转 | as | 可能截断/静默 | x as u8、引用→裸指针 |
四、在函数签名里的用法
rust
// 参数写 impl Into<String>:调用处能传 String 也能传 &str,最省事
fn greet(name: impl Into<String>) {
let name = name.into();
println!("hi {name}");
}
greet("alice");
greet(String::from("bob"));五、常见坑
- 手写 Into 而不写 From:违反惯例还拿不到 From 那半边,统一实现 From。
- 用
as做可能截断的数值转换:500i64 as u8静默变成 244,收窄用try_from并处理 Err。 - 把可能失败的转换塞进 From:From 契约是必成功,会失败的用 TryFrom。
into()类型推不出来:编译器不知道目标类型时标注let x: T = v.into()。- 混淆 parse 与 From:字符串解析是
FromStr/parse(带 Result),不是 From。 - 为转换写大量构造函数:优先实现标准转换 trait,生态(
?、泛型约束)才能复用。
总结
Rust 用 trait 而非隐式规则做转换:实现 From<A> for B 会自动获得 Into<B> for A,故惯例只写 From,From/Into 表示必然成功、通常无损的转换(String::from、i32→i64、? 的错误提升都靠它);可能失败或收窄的用 TryFrom/TryInto 返回 Result,字符串解析用 FromStr 的 parse、转字符串靠 Display 得到的 to_string,而 as 只用于原始类型强转且会静默截断,数值收窄应改用 try_from 并处理错误。