新语言特性
> 掌握 Rust 2024 Edition 引入的重要新特性。
异步闭包
问题场景
在 Rust 2024 之前,异步闭包需要变通方案:
rust
▶ Run// ❌ Rust 2021: 异步闭包不支持
let async_closure = async |x| { // 编译错误
some_async_fn(x).await
};
// ✅ 变通方案:使用 async 块
let closure = |x| async {
some_async_fn(x).await
};Rust 2024: 原生异步闭包
rust
▶ Run// ✅ Rust 2024: 原生支持异步闭包
let async_closure = async |x: i32| -> i32 {
some_async_fn(x).await
};
// 使用异步闭包
let result = async_closure(42).await;异步闭包语法
rust
▶ Run// 1. 基本语法
let f = async || {
// 异步代码
};
// 2. 带参数
let add = async |a: i32, b: i32| {
async_add(a, b).await
};
// 3. 带返回类型标注
let process = async |data: Vec<u8>| -> Result<String, Error> {
parse_async(data).await
};
// 4. move 关键字
let value = 42;
let closure = async move || {
consume(value).await // value 被移动到闭包中
};实际应用
rust
▶ Runuse tokio::net::TcpStream;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
// ✅ 使用异步闭包创建处理器
let handle_client = async |mut stream: TcpStream| {
let mut buf = [0; 1024];
let n = stream.read(&mut buf).await?;
stream.write_all(&buf[..n]).await?;
Ok::<_, std::io::Error>(())
};
// 批量处理连接
let handlers: Vec<_> = connections
.into_iter()
.map(handle_client)
.collect();
futures::future::join_all(handlers).await;impl Trait 改进
返回位置 impl Trait
rust
▶ Run// Rust 2021: impl Trait 只能在返回位置
fn get_iter() -> impl Iterator<Item = i32> {
vec![1, 2, 3].into_iter()
}
// Rust 2024: 更灵活的使用场景
fn conditional_iter(condition: bool) -> impl Iterator<Item = i32> {
if condition {
vec![1, 2, 3].into_iter()
} else {
vec![4, 5, 6].into_iter()
}
}参数位置 impl Trait
rust
▶ Run// ✅ Rust 2024: 参数位置使用 impl Trait
fn process(data: impl IntoIterator<Item = i32>) -> i32 {
data.into_iter().sum()
}
// 等价于泛型函数,但语法更简洁
fn process_generic<T: IntoIterator<Item = i32>>(data: T) -> i32 {
data.into_iter().sum()
}
// 调用
process(vec![1, 2, 3]);
process([1, 2, 3]);
process(1..=3);impl Trait 与生命周期
rust
▶ Run// ✅ Rust 2024: 更好的生命周期推断
fn filter_positive<'a>(
data: &'a [i32]
) -> impl Iterator<Item = i32> + 'a {
data.iter().copied().filter(|&x| x > 0)
}
// 使用 RPITIT(Return Position Impl Trait In Trait)
trait DataProcessor {
fn process(&self, data: &[i32]) -> impl Iterator<Item = i32>;
}
struct MyProcessor;
impl DataProcessor for MyProcessor {
fn process(&self, data: &[i32]) -> impl Iterator<Item = i32> {
data.iter().copied().filter(|&x| x > 0)
}
}捕获规则改进
rust
▶ Run// Rust 2021: impl Trait 捕获所有泛型参数
fn foo<T>(x: T) -> impl Sized { x }
// Rust 2024: 更精确的捕获控制
fn bar<T>(x: T) -> impl Sized + use<T> { x }
// 显式声明捕获 T ^^^^^
// 示例:避免不必要的捕获
fn process(data: Vec<i32>) -> impl Iterator<Item = i32> {
data.into_iter().filter(|x| *x > 0)
// 只捕获 Item = i32,不捕获其他类型参数
}模式匹配增强
if let 模式链
rust
▶ Run// ✅ Rust 2024: 支持多个 if let 模式
fn process_value(value: Option<Result<i32, String>>) {
if let Some(Ok(n)) = value {
println!("Got value: {}", n);
}
// 链式模式匹配
if let Some(Ok(n)) = value
&& n > 0
&& n < 100
{
println!("Valid positive number: {}", n);
}
}let-else 模式
rust
▶ Run// ✅ let-else 语法
fn process(input: Option<i32>) -> Result<i32, String> {
let Some(value) = input else {
return Err("No value provided".to_string());
};
let checked = if value > 0 { value } else {
return Err("Value must be positive".to_string());
};
Ok(checked * 2)
}模式中的 or 模式
rust
▶ Run// ✅ Rust 2024: or 模式增强
enum Color {
Rgb(u8, u8, u8),
Hsv(u8, u8, u8),
}
fn is_red(color: Color) -> bool {
match color {
Color::Rgb(255, 0, 0) | Color::Rgb(255, _, _) => true,
Color::Hsv(0, 100, 100) => true,
_ => false,
}
}
// 绑定变量
fn get_brightness(color: Color) -> u8 {
match color {
Color::Rgb(_, _, b) | Color::Hsv(_, _, b) => b,
// 相同变量名 ^^^^^
}
}范围模式
rust
▶ Run// ✅ Rust 2024: 更强大的范围模式
fn classify(value: i32) -> &'static str {
match value {
0..=9 => "single digit",
10..=99 => "double digit",
100..=999 => "triple digit",
_ => "large number",
}
}
// 字符范围
fn is_vowel(c: char) -> bool {
matches!(c, 'a'..='z' | 'A'..='Z')
}其他改进
1. gen 闭包(实验性)
rust
▶ Run// ✅ Rust 2024: gen 闭包(需要 feature gate)
#![feature(gen_blocks)]
fn generate_numbers() -> impl Iterator<Item = i32> {
gen {
let mut i = 0;
loop {
yield i;
i += 1;
}
}
}2. unsafe 操作符
rust
▶ Run// ✅ Rust 2024: 更明确的 unsafe 标记
let value = unsafe { *ptr }; // 显式的 unsafe 块
// unsafe 函数调用
unsafe fn dangerous() {}
unsafe {
dangerous(); // 必须在 unsafe 块中调用
}3. format_args_capture
rust
▶ Run// ✅ Rust 2024: 在格式化字符串中捕获变量
let name = "Alice";
let age = 30;
// 旧方式
println!("Name: {}, Age: {}", name, age);
// 新方式:直接捕获
println!("Name: {name}, Age: {age}");
// 直接使用变量名 ^^^^ ^^^迁移建议
利用新特性的重构
rust
▶ Run// ❌ Rust 2021
fn get_data() -> Box<dyn Iterator<Item = i32>> {
Box::new(vec![1, 2, 3].into_iter())
}
// ✅ Rust 2024
fn get_data() -> impl Iterator<Item = i32> {
vec![1, 2, 3].into_iter()
}简化错误处理
rust
▶ Run// ❌ Rust 2021: 嵌套 match
fn process(data: Option<Result<i32, Error>>) -> Result<i32, Error> {
match data {
Some(result) => match result {
Ok(value) => Ok(value),
Err(e) => Err(e),
},
None => Err(Error::NoData),
}
}
// ✅ Rust 2024: 链式 if let
fn process(data: Option<Result<i32, Error>>) -> Result<i32, Error> {
let Some(Ok(value)) = data else {
return Err(Error::NoData);
};
Ok(value)
}最佳实践
1. 使用异步闭包替代闭包返回 future
rust
▶ Run// ❌ 旧方式
let handler = |x| async move {
process(x).await
};
// ✅ 新方式
let handler = async |x| {
process(x).await
};2. 优先使用 impl Trait
rust
▶ Run// ❌ 返回具体类型
fn get_iter() -> std::vec::IntoIter<i32> {
vec![1, 2, 3].into_iter()
}
// ✅ 返回 impl Trait
fn get_iter() -> impl Iterator<Item = i32> {
vec![1, 2, 3].into_iter()
}3. 利用模式匹配简化代码
rust
▶ Run// ❌ 多层嵌套
if let Some(x) = option {
if x > 0 {
if x < 100 {
// ...
}
}
}
// ✅ 链式模式
if let Some(x) = option
&& x > 0
&& x < 100
{
// ...
}小结
Rust 2024 Edition 的关键改进:
| 特性 | 用途 | 优势 |
|---|---|---|
| 异步闭包 | 定义异步闭包 | 更自然的异步代码 |
| impl Trait 增强 | 类型抽象 | 简化泛型代码 |
| 模式匹配增强 | 条件匹配 | 减少嵌套,更清晰 |
| 格式化捕获 | 格式化字符串 | 减少重复参数 |
迁移提示:
- 大部分代码无需修改即可迁移
- 使用
cargo fix --edition自动修复 - 逐步采用新特性改进代码
下一步: 下一节我们将学习现代 crate 生态的最佳实践。
练习
练习 1:异步闭包
编写一个异步闭包,模拟并发请求:
rust
▶ Run// TODO: 实现 fetch_all 函数
async fn fetch_all(urls: Vec<&str>) -> Vec<Result<String, Error>> {
// 使用异步闭包并发请求
}练习 2:impl Trait
重构以下函数,使用 impl Trait:
rust
▶ Run// 提示:简化返回类型
fn get_numbers() -> std::vec::IntoIter<i32> {
vec![1, 2, 3, 4, 5].into_iter()
}练习 3:模式匹配
使用链式 if let 重构以下代码:
rust
▶ Runfn process(data: Option<Result<i32, String>>) {
match data {
Some(Ok(n)) if n > 0 => println!("Positive: {}", n),
_ => println!("Invalid"),
}
}