跳转到正文
zeno's blog
返回

Rust 基础:类型转换 as、From/Into 与 Turbofish

专题: Rust 基础

Table of contents

Open Table of contents

as:原始类型强转

编译器内置的转换,仅限原始类型(整数、浮点、指针),和任何 trait 无关。

let x: i32 = 42;
let y: f64 = x as f64;       // 整数 → 浮点
let z: u8 = x as u8;         // i32 → u8(截断,只保留低 8 位)
let b: u8 = 256_i32 as u8;   // 得到 0!静默截断,不报错
let c: i8 = 200_u8 as i8;    // 得到 -56!溢出,不报错

let p = &x as *const i32;    // 引用 → 裸指针
let n = p as usize;          // 指针 → 整数

不能做的事

let s: String = 42 as String;         // 编译错误!String 不是原始类型
let p: Player = row as Player;        // 编译错误!自定义类型不行

注意as 会静默丢数据,是 Rust 里少数不安全的操作之一。

From / Into:trait 方法,类型安全

// From:从另一个类型构造自己
let s: String = String::from(42);       // 调 From<i32> for String
let id: PlayerId = PlayerId::from(42);  // 调 From<u32> for PlayerId

// Into:把自己转成另一个类型(From 的反向,自动生成)
let s: String = 42.into();             // 等价于 String::from(42)
let id: PlayerId = 42_u32.into();      // 等价于 PlayerId::from(42)

// ? 操作符内部也是调 From::from
let err: AppError = sqlx_error.into();  // 或者 ? 自动调用

和 as 的关系:没有任何关系。as 不会调用 From/Into

TryFrom / TryInto:可能失败的转换

let n: u8 = u8::try_from(256_i32);  // Err!256 超出 u8 范围
let n: u8 = 256_i32 as u8;          // 0!as 静默截断

// 所以实际项目中优先用 TryFrom
let port: u16 = raw_port.try_into()?;  // 超出范围会返回 Err

Turbofish ::<>:告诉编译器泛型类型参数

不是类型转换,是泛型调用的显式类型标注

// parse 的签名:fn parse<F: FromStr>(&self) -> Result<F, F::Err>
// 编译器需要知道 F 是什么类型

// 方式 1:从变量类型标注推断
let n: u32 = "42".parse().unwrap();  // 编译器从 `: u32` 推断 F = u32

// 方式 2:turbofish 直接指定
let n = "42".parse::<u32>().unwrap();  // 直接告诉 parse:F = u32

// 没有任何类型信息时:
let n = "42".parse().unwrap();  // 编译错误!F 是什么?

常见使用场景

// collect:编译器不知道你要收集成什么容器
let nums = vec![1, 2, 3];
let strings = nums.iter().map(|n| n.to_string()).collect::<Vec<String>>();

// channel:编译器不知道传什么类型
let (tx, rx) = tokio::sync::mpsc::channel::<Message>(32);

// 链式调用中间无法标注类型,只能用 turbofish
let result = "3.14".parse::<f64>().unwrap().sqrt();

叫 turbofish 是因为 ::<> 长得像一条鱼。社区绰号,不是官方术语。

对比

语法           是什么             能做什么                    会丢数据吗
──────────────────────────────────────────────────────────────────────
as             编译器内置强转     原始类型互转(数值、指针)    会,静默截断
From/Into      trait 方法调用    任何类型间的安全转换          不会
TryFrom/Into   trait 方法调用    可能失败的转换,返回 Result   不会,失败返回 Err
::<> turbofish 类型标注语法      告诉编译器泛型参数是什么       不涉及转换

分享这篇文章:

上一篇
Rust 异步生态(总览):从 mio 到 axum 的分层架构
下一篇
Rust 基础:类型获得 Trait 方法的三种方式