Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

English Original

11. From 与 Into 特征 🟢

你将学到:

  • 使用 FromInto 实现零成本类型转换
  • TryFromTryInto 处理可能失败的转换
  • 字符串转换三要素 (to_string, parse, format!)

Rust 里的类型转换

Python 通过各种构造函数 (如 int("42"), str(42)) 来处理转换。而 Rust 使用 FromInto 两个特征来规定一种类型如何安全、高效地转换为另一种类型。

实现 From

如果你为类型 B 实现了 From<A>,编译器会自动为你为 A 实现 Into<B>

#![allow(unused)]
fn main() {
struct Seconds(i32);
struct Minutes(i32);

impl From<Minutes> for Seconds {
    fn from(m: Minutes) -> Self {
        Seconds(m.0 * 60)
    }
}

// 现在两种方式都行:
let s1 = Seconds::from(Minutes(1)); // 显式 From
let s2: Seconds = Minutes(5).into(); // 自动推理出的 Into
}

TryFrom:可能失败的转换

并非所有转换都是百分之百成功的 (比如把一个很大的 i64 转成 i8)。Python 这种情况下会抛出异常;而在 Rust 里,这些方法会返回一个 Result

#![allow(unused)]
fn main() {
use std::convert::TryInto;

let my_i64: i64 = 100;
let my_i8: Result<i8, _> = my_i64.try_into();

match my_i8 {
    Ok(n) => println!("成功转换: {n}"),
    Err(_) => println!("数值太大,i8 放不下!"),
}
}

字符串转换:最常用的三个模式

1. 任意类型 → 字符串 (to_string)

前提是你要为该类型实现 Display 特征(或者该类型是原生基础类型)。

#![allow(unused)]
fn main() {
let s = 42.to_string();
}

2. 字符串 → 其它类型 (parse)

前提是目标类型实现了 FromStr。注意这会返回一个 Result

#![allow(unused)]
fn main() {
let n: i32 = "42".parse().expect("这不是个数字!");
}

3. &str 与 String 互转

  • String::from("你好"): 把字符串切片变成拥有的字符串。
  • s.as_str(): 把拥有的字符串借出成切片。

快速转换参考表

PythonRust结果类型
str(x)x.to_string()String
int(s)s.parse::<i32>()Result<i32, ...>
float(s)s.parse::<f64>()Result<f64, ...>
list(range(5))(0..5).collect::<Vec<_>>()Vec<i32>
MyClass(old_obj)MyClass::from(old_obj)MyClass

练习

🏋️ 练习:从元组创建 Point (点击展开)

挑战:定义一个结构体 Point { x: i32, y: i32 }。为它实现 From<(i32, i32)> 特征。测试时,将元组 (10, 20) 通过 .into() 转换成 Point 类型。

参考答案
#[derive(Debug)]
struct Point { x: i32, y: i32 }

impl From<(i32, i32)> for Point {
    fn from(tuple: (i32, i32)) -> Self {
        Point { x: tuple.0, y: tuple.1 }
    }
}

fn main() {
    let p: Point = (10, 20).into();
    println!("{:?}", p);
}