Rust插件库bae的使用:高效扩展Rust功能的轻量级工具包
Rust插件库bae的使用:高效扩展Rust功能的轻量级工具包
bae
是一个为proc macro作者设计的crate,它简化了属性的解析过程。虽然受到darling
的启发,但提供了更简单的API。
安装
在项目目录中运行以下Cargo命令:
cargo add bae
或者在你的Cargo.toml中添加以下行:
bae = "0.1.7"
示例用法
下面是一个使用bae的完整示例demo,展示如何定义和解析自定义属性:
use bae::FromAttributes;
use syn::{parse_macro_input, DeriveInput};
// 定义一个可以解析的结构体
#[derive(FromAttributes)]
struct MyAttributes {
#[bae(default)]
name: Option<String>,
#[bae(default = "0")]
count: usize,
enabled: bool,
}
// 自定义派生宏示例
#[proc_macro_derive(MyDerive, attributes(my_attr))]
pub fn my_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
// 解析属性
let attrs = MyAttributes::from_attributes(&input.attrs).unwrap();
// 使用解析出的属性
println!("name: {:?}", attrs.name);
println!("count: {}", attrs.count);
println!("enabled: {}", attrs.enabled);
proc_macro::TokenStream::new()
}
在这个示例中:
- 我们定义了一个
MyAttributes
结构体,使用#[derive(FromAttributes)]
自动实现属性解析 - 结构体字段可以有不同的属性:
name
字段是可选的(Option),如果没有提供则默认为Nonecount
字段有默认值"0"enabled
字段是必须提供的
- 在proc macro中,我们可以轻松地从DeriveInput中解析出这些属性
bae的设计目标是保持简单和轻量级,同时提供必要的功能来解析proc macro中的属性。它特别适合那些需要自定义属性但不想处理复杂解析逻辑的macro作者。
完整示例代码
下面是一个更完整的示例,展示如何使用bae创建一个自定义派生宏:
// 导入必要的库
use bae::FromAttributes;
use syn::{parse_macro_input, DeriveInput};
use quote::quote;
// 定义属性结构体
#[derive(FromAttributes)]
struct MyConfig {
#[bae(default = "\"default_name\".to_string()")]
name: String,
#[bae(default)]
id: Option<u32>,
#[bae(default = "true")]
debug: bool,
}
// 自定义派生宏实现
#[proc_macro_derive(MyMacro, attributes(my_config))]
pub fn my_macro_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
// 解析输入为DeriveInput
let input = parse_macro_input!(input as DeriveInput);
// 解析自定义属性
let config = MyConfig::from_attributes(&input.attrs)
.expect("Failed to parse attributes");
// 获取结构体名称
let name = input.ident;
// 生成实现代码
let expanded = quote! {
impl #name {
fn print_config(&self) {
println!("Name: {}", #config.name);
println!("ID: {:?}", #config.id);
println!("Debug mode: {}", #config.debug);
}
}
};
// 返回生成的token stream
proc_macro::TokenStream::from(expanded)
}
这个示例展示了:
- 如何定义带有默认值的属性配置
- 如何处理可选属性
- 如何使用quote crate生成代码
- 如何将解析的属性应用到生成的代码中
使用示例:
#[derive(MyMacro)]
#[my_config(name = "custom_name", id = 42)]
struct MyStruct;
let s = MyStruct;
s.print_config();
// 输出:
// Name: custom_name
// ID: Some(42)
// Debug mode: true
1 回复
Rust插件库bae的使用:高效扩展Rust功能的轻量级工具包
简介
bae是一个轻量级的Rust插件库,旨在通过简单易用的接口扩展Rust的核心功能。它提供了一系列实用工具和扩展方法,可以帮助开发者提高编码效率,减少样板代码。
主要特性
- 轻量级设计,无额外依赖
- 提供常用功能的扩展实现
- 简化常见编程模式
- 完全兼容标准库
安装方法
在Cargo.toml中添加依赖:
[dependencies]
bae = "0.3.0"
核心功能及使用示例
1. 集合操作扩展
use bae::collections::ExtendedIter;
fn main() {
let numbers = vec![1, 2, 3, 4, 5];
// 查找并转换
let result = numbers.find_map(|x| if x > 3 { Some(x * 2) } else { None });
println!("{:?}", result); // 输出: Some(8)
// 安全获取
let safe_get = numbers.get_or(2, &99);
println!("{}", safe_get); // 输出: 3
let safe_get = numbers.get_or(10, &99);
println!("{}", safe_get); // 输出: 99
}
2. 字符串处理
use bae::string::StringExt;
fn main() {
let s = "hello world".to_string();
// 安全截取
println!("{}", s.safe_slice(0..5)); // 输出: hello
println!("{}", s.safe_slice(6..15)); // 输出: world (自动处理越界)
// 快速重复
println!("{}", s.repeat_to(3)); // 输出: hello worldhello worldhello world
}
3. Option和Result扩展
use bae::option::OptionExt;
use bae::result::ResultExt;
fn main() {
// Option扩展
let some_val: Option<i32> = Some(42);
let none_val: Option<i32> = None;
println!("{}", some_val.unwrap_or_default()); // 输出: 42
println!("{}", none_val.unwrap_or_default()); // 输出: 0
// Result扩展
let ok_result: Result<i32, &str> = Ok(42);
let err_result: Result<i32, &str> = Err("error");
println!("{:?}", ok_result.map_err_to_string()); // 输出: Ok(42)
println!("{:?}", err_result.map_err_to_string()); // 输出: Err("error")
}
4. 数学运算扩展
use bae::num::NumExt;
fn main() {
// 数字扩展
let x = 5;
println!("{}", x.clamp(2, 10)); // 输出: 5
println!("{}", x.clamp(6, 10)); // 输出: 6
// 百分比计算
println!("{}", 50.percent_of(200)); // 输出: 极好的,100.0
}
5. 异步工具
use bae::async_tools::AsyncExt;
use std::time::Duration;
#[tokio::main]
async fn main() {
// 带超时的异步操作
let result = async {
tokio::time::sleep(Duration::from_secs(2)).await;
42
}.timeout(Duration::from_secs(1)).await;
println!("{:?}", result); // 输出: Err(TimeoutError)
}
最佳实践
-
按需导入:只导入需要的模块,避免全局导入
use bae::collections::ExtendedIter;
-
链式调用:充分利用bae的链式调用特性
vec![1, 2, 3].filter(|x| x > 1).find_map(|x| Some(x * 2));
-
错误处理:使用bae提供的错误处理扩展简化代码
result.map_err_to_string().unwrap_or_default();
性能考虑
bae在设计时充分考虑了性能:
- 所有扩展方法都是零成本的抽象
- 避免不必要的内存分配
- 提供直接操作底层数据的接口
总结
bae是一个简单但功能强大的Rust扩展库,通过提供一系列实用的扩展方法,可以显著提高开发效率。它的轻量级设计使其成为任何Rust项目的理想补充,而不会增加显著的编译时间或二进制大小。
完整示例demo
下面是一个综合使用bae库多个功能的完整示例:
use bae::collections::ExtendedIter;
use bae::string::StringExt;
use bae::num::NumExt;
use bae::async_tools::AsyncExt;
use std::time::Duration;
#[tokio::main]
async fn main() {
// 1. 集合操作示例
let numbers = vec![10, 20, 30, 40, 50];
let doubled = numbers.find_map(|x| if x > 25 { Some(x * 2) } else { None });
println!("第一个大于25的数字加倍后: {:?}", doubled); // 输出: Some(60)
// 2. 字符串处理示例
let greeting = "Hello, Rust!".to_string();
println!("截取字符串: {}", greeting.safe_slice(0..5)); // 输出: Hello
println!("重复字符串: {}", greeting.repeat_to(2)); // 输出: Hello, Rust!Hello, Rust!
// 3. 数字处理示例
let value = 75;
println!("75是200的{}%", value.percent_of(200)); // 输出: 37.5
println!("限制范围: {}", value.clamp(80, 100)); // 输出: 80
// 4. 异步超时示例
let async_result = async {
tokio::time::sleep(Duration::from_secs(3)).await;
"操作完成"
}.timeout(Duration::from_secs(2)).await;
match async_result {
Ok(msg) => println!("{}", msg),
Err(_) => println!("操作超时"), // 输出: 操作超时
}
}
这个完整示例展示了如何在一个程序中综合使用bae库的多个功能模块,包括集合操作、字符串处理、数字计算和异步工具。