Rust轻量级异步宏库smol-macros的使用,简化异步编程与代码生成
Rust轻量级异步宏库smol-macros的使用,简化异步编程与代码生成
smol-macros是一个为smol-rs提供宏支持的库,它可以帮助快速搭建高效的异步运行时,简化异步编程。
简单执行器
使用main!
宏可以轻松创建异步main函数:
use smol-macros::main;
main! {
async fn main() {
println!("Hello, world!");
}
}
使用proc宏语法
如果更喜欢proc宏风格,可以使用macro_rules_attribute::apply
:
use macro_rules_attribute::apply;
use smol-macros::main;
#[apply(main!)]
async fn main() {
println!("Hello, world!");
}
基于任务的执行器
当函数第一个参数是Executor
时,会自动创建执行器:
use macro_rules_attribute::apply;
use smol-macros::{main, Executor};
#[apply(main!)]
async fn main(ex: &Executor<'_>) {
ex.spawn(async { println!("Hello world!"); }).await;
}
使用线程安全的Executor
会创建线程池,而LocalExecutor
则不会创建线程。
测试
使用test!
宏创建包含执行器的测试用例:
use macro_rules_attribute::apply;
use smol-macros::{test, Executor};
#[apply(test!)]
async fn do_test(ex: &Executor<'_>) {
ex.spawn(async {
assert_eq!(1 + 1, 2);
}).await;
}
MSRV策略
最低支持的Rust版本是1.63。MSRV不会超过Debian Stable提供的Rust版本。
完整示例
以下是使用smol-macros的完整示例:
use smol-macros::{main, Executor};
// 简单异步main函数示例
main! {
async fn main() {
println!("Starting the async program...");
// 使用执行器示例
async_main().await;
}
}
// 使用执行器的异步函数
async fn async_main() {
let ex = Executor::new();
// 创建多个异步任务
let task1 = ex.spawn(async {
println!("Task 1 running");
1
});
let task2 = ex.spawn(async {
println!("Task 2 running");
2
});
// 等待任务完成
let result1 = task1.await;
let result2 = task2.await;
println!("Results: {}, {}", result1, result2);
}
// 测试示例
#[cfg(test)]
mod tests {
use super::*;
use smol-macros::test;
#[test]
async fn test_async_addition() {
let ex = Executor::new();
let result = ex.spawn(async {
1 + 1
}).await;
assert_eq!(result, 2);
}
}
这个示例展示了:
- 使用
main!
宏创建异步main函数 - 使用执行器创建和管理异步任务
- 编写异步测试用例
- 任务间的await操作
要使用这个库,请在Cargo.toml中添加:
smol-macros = "0.1.1"
Rust轻量级异步宏库smol-macros的使用
介绍
smol-macros 是一个轻量级的 Rust 异步宏库,旨在简化异步编程和代码生成。它基于 smol 异步运行时,提供了一组方便的宏来减少异步代码的样板代码量,使异步编程更加简洁和直观。
主要特性
- 简化异步代码结构
- 减少样板代码
- 与 smol 运行时无缝集成
- 轻量级且高效
安装
在 Cargo.toml 中添加依赖:
[dependencies]
smol-macros = "0.1"
使用方法
1. async!
宏
简化异步块的创建:
use smol_macros::async;
fn main() {
let task = async! {
println!("Hello from async block!");
42
};
let result = smol::block_on(task);
println!("Result: {}", result);
}
2. spawn!
宏
简化异步任务的生成:
use smol_macros::spawn;
fn main() {
let handle = spawn! {
println!("Running in spawned task");
"Task completed"
};
let result = smol::block_on(handle);
println!("{}", result);
}
3. select!
宏
简化多个异步操作的选择:
use smol_macros::select;
use std::time::Duration;
async fn timeout() -> &'static str {
smol::Timer::after(Duration::from_secs(2)).await;
"timeout"
}
async fn computation() -> &'static str {
smol::Timer::after(Duration::from_secs(1)).await;
"computation"
}
fn main() {
smol::block_on(async! {
let result = select! {
res = timeout() => res,
res = computation() => res,
};
println!("First result: {}", result);
});
}
4. try!
宏的异步版本
简化异步错误处理:
use smol_macros::try_async;
async fn might_fail(succeed: bool) -> Result<i32, &'static str> {
if succeed {
Ok(42)
} else {
Err("Something went wrong")
}
}
fn main() {
smol::block_on(async! {
let result: i32 = try_async!(might_fail(true));
println!("Result: {}", result);
// 下面这行会提前返回错误
let _ = try_async!(might_fail(false));
println!("This won't be printed");
});
}
高级用法
结合多个宏使用
use smol_macros::{async, spawn, select};
async fn task_one() -> &'static str {
smol::Timer::after(std::time::Duration::from_secs(1)).await;
"Task one completed"
}
async fn task_two() -> &'static str {
smol::Timer::after(std::time::Duration::from_secs(2)).await;
"Task two completed"
}
fn main() {
let main_task = async! {
let handle1 = spawn!(task_one());
let handle2 = spawn!(task_two());
select! {
res = handle1 => println!("{}", res),
res = handle2 => println!("{}", res),
}
};
smol::block_on(main_task);
}
注意事项
- smol-macros 主要设计用于 smol 运行时,但也可以与其他兼容的运行时一起使用
- 宏展开后的代码可能会影响错误消息的可读性
- 在复杂场景下,直接使用原始 Future trait 可能更灵活
smol-macros 通过提供这些简洁的宏,显著减少了异步编程中的样板代码,使开发者能够更专注于业务逻辑而不是异步机制的低级细节。
完整示例代码
下面是一个综合使用smol-macros各种宏的完整示例:
use smol_macros::{async, spawn, select, try_async};
use std::time::Duration;
// 异步函数示例1:模拟网络请求
async fn fetch_data() -> Result<String, &'static str> {
smol::Timer::after(Duration::from_secs(1)).await;
Ok("Data fetched successfully".to_string())
}
// 异步函数示例2:模拟数据库查询
async fn query_database() -> Result<i32, &'static str> {
smol::Timer::after(Duration::from_secs(2)).await;
Ok(100)
}
// 异步函数示例3:模拟超时操作
async fn timeout_operation() -> &'static str {
smol::Timer::after(Duration::from_secs(3)).await;
"Operation timed out"
}
fn main() {
// 使用async!宏创建主异步块
let main_task = async! {
// 使用spawn!宏并发执行多个任务
let fetch_task = spawn!(fetch_data());
let db_task = spawn!(query_database());
let timeout_task = spawn!(timeout_operation());
// 使用select!宏等待第一个完成的任务
let first_result = select! {
res = fetch_task => res.map(|s| format!("Fetch result: {}", s)),
res = db_task => res.map(|n| format!("DB result: {}", n)),
res = timeout_task => Ok(format!("Timeout: {}", res)),
};
// 使用try_async!宏处理可能错误的结果
let result = try_async!(first_result);
println!("First completed: {}", result);
// 等待剩余任务完成
let remaining_results = select! {
res = fetch_task => res,
res = db_task => res,
};
match remaining_results {
Ok(res) => println!("Remaining result: {:?}", res),
Err(e) => println!("Error: {}", e),
}
};
// 使用smol运行时执行主任务
smol::block_on(main_task);
}
代码说明
-
定义了三个异步函数模拟不同操作:
fetch_data()
: 模拟网络请求,1秒后返回成功数据query_database()
: 模拟数据库查询,2秒后返回结果timeout_operation()
: 模拟超时操作,3秒后返回超时信息
-
主函数中使用
async!
宏创建主异步块 -
使用
spawn!
宏并发执行三个异步任务 -
使用
select!
宏选择最先完成的任务 -
使用
try_async!
宏处理可能错误的结果 -
最后处理剩余未完成的任务
这个示例展示了如何组合使用smol-macros提供的各种宏来构建复杂的异步逻辑,同时保持代码的简洁性和可读性。