Rust From 与 Into Trait
你将学到: Rust 的类型转换 Trait——用于不会失败的转换的
From<T>和Into<T>,用于可能失败的TryFrom和TryInto。实现From即可免费获得Into。替代 C++ 转换运算符和构造函数。
From和Into是便于类型转换的互补 Trait- 类型通常实现
FromTrait。String::from("Rust")将&str转换为String。 当存在From<T> for U时,Rust 还提供Into<U> for T,因此let s: String = "Rust".into();也能工作。
struct Point {x: u32, y: u32}
// Construct a Point from a tuple
impl From<(u32, u32)> for Point {
fn from(xy : (u32, u32)) -> Self {
Point {x : xy.0, y: xy.1} // Construct Point using the tuple elements
}
}
fn main() {
let s = String::from("Rust");
let x = u32::from(true);
let p = Point::from((40, 42));
// let p : Point = (40,42).into(); // Alternate form of the above
println!("s: {s} x:{x} p.x:{} p.y {}", p.x, p.y);
}
练习:From 与 Into
- 为
Point实现FromTrait,转换为名为TransposePoint的类型。TransposePoint交换Point的x和y元素
Solution (click to expand)
struct Point { x: u32, y: u32 }
struct TransposePoint { x: u32, y: u32 }
impl From<Point> for TransposePoint {
fn from(p: Point) -> Self {
TransposePoint { x: p.y, y: p.x }
}
}
fn main() {
let p = Point { x: 10, y: 20 };
let tp = TransposePoint::from(p);
println!("Transposed: x={}, y={}", tp.x, tp.y); // x=20, y=10
// Using .into() — works automatically when From is implemented
let p2 = Point { x: 3, y: 7 };
let tp2: TransposePoint = p2.into();
println!("Transposed: x={}, y={}", tp2.x, tp2.y); // x=7, y=3
}
// Output:
// Transposed: x=20, y=10
// Transposed: x=7, y=3
Rust Default Trait
Default可用于为类型实现默认值- 类型可使用
Derive宏配合Default,或提供自定义实现
- 类型可使用
#[derive(Default, Debug)]
struct Point {x: u32, y: u32}
#[derive(Debug)]
struct CustomPoint {x: u32, y: u32}
impl Default for CustomPoint {
fn default() -> Self {
CustomPoint {x: 42, y: 42}
}
}
fn main() {
let x = Point::default(); // Creates a Point{0, 0}
println!("{x:?}");
let y = CustomPoint::default();
println!("{y:?}");
}
Rust Default Trait
DefaultTrait 有多种用途,包括- 执行部分复制,其余用默认初始化
- 作为
Option类型在unwrap_or_default()等方法中的默认替代
#[derive(Debug)]
struct CustomPoint {x: u32, y: u32}
impl Default for CustomPoint {
fn default() -> Self {
CustomPoint {x: 42, y: 42}
}
}
fn main() {
let x = CustomPoint::default();
// Override y, but leave rest of elements as the default
let y = CustomPoint {y: 43, ..CustomPoint::default()};
println!("{x:?} {y:?}");
let z : Option<CustomPoint> = None;
// Try changing the unwrap_or_default() to unwrap()
println!("{:?}", z.unwrap_or_default());
}
其他 Rust 类型转换
- Rust 不支持隐式类型转换,
as可用于显式转换 as应谨慎使用,因为它可能因窄化等导致数据丢失。一般而言,尽可能使用into()或from()
fn main() {
let f = 42u8;
// let g : u32 = f; // Will not compile
let g = f as u32; // Ok, but not preferred. Subject to rules around narrowing
let g : u32 = f.into(); // Most preferred form; infallible and checked by the compiler
// let k : u8 = g.into(); // Fails to compile; narrowing can result in loss of data
// Attempting a narrowing operation requires use of try_into
if let Ok(k) = TryInto::<u8>::try_into(g) {
println!("{k}");
}
}