Rust 声明式宏元变量(Fragment Specifiers)深度解析
item
在 Rust 中,item 代表 crate 中的一个顶层组件,例如模块、函数、结构体、枚举、常量、trait 等。可以将 crate 视为一个包含多个 item 的集合。
macro_rules! define_item {
($component:item) => {
$component
};
}
define_item!(
#[derive(Debug, Clone)]
struct NetworkConfig {
ip: String,
port: u16,
}
);
define_item!(
fn calculate_sum(a: i32, b: i32) -> i32 {
a + b
}
);
define_item!(
mod network_utils {}
);
fn main() {
let config = NetworkConfig { ip: "127.0.0.1".into(), port: 8080 };
println!("{:?}", config);
println!("Sum: {}", calculate_sum(10, 20));
}
block
block 匹配一个由花括号 {} 包裹的匿名命名空间作用域,内部可以包含多条语句和最终的表达式。
macro_rules! execute_block {
($body:block) => {
$body
};
}
fn main() {
let result = execute_block!({
let x = 10;
let y = 20;
x * y
});
println!("Result: {}", result);
}
stmt
stmt 用于匹配语句(Statement)。它可以是 item、let 绑定、表达式语句或宏调用。需要注意的是,语句在宏匹配时通常不包含尾随的分号。
macro_rules! process_stmt {
($statement:stmt) => {
$statement
};
}
fn main() {
// let 绑定
process_stmt!(let max_retries = 5);
// item
process_stmt!(struct RetryConfig { delay: u64 });
// 表达式语句
process_stmt!(
if max_retries > 0 {
println!("Retrying...");
}
);
// 宏调用
process_stmt!(println!("Statement processed"));
}
pat_param
pat_param 用于匹配模式(Pattern),常用于 match 表达式或 if let 的左侧。与 pat 不同,pat_param 默认不支持 or-pattern(即使用 | 分隔的多个模式)。
macro_rules! check_pattern_param {
($p:pat_param) => {
$p
};
}
enum Status {
Active,
Inactive,
Pending(u32),
}
fn main() {
let status = Status::Pending(42);
if let check_pattern_param!(Status::Pending(code)) = status {
println!("Pending with code: {}", code);
}
}
pat
pat 同样用于匹配模式,但它支持更广泛的模式类型,包括 or-pattern(例如 A | B)。
macro_rules! match_complex_pattern {
($pattern:pat) => {
$pattern
};
}
fn main() {
let value = 2;
match value {
match_complex_pattern!(0 | 1 | 2) => println!("Low value"),
_ => println!("High value"),
}
}
expr
expr 匹配任何合法的 Rust 表达式(Expression),包括字面量、路径、运算符表达式、函数调用、闭包、控制流表达式等。
macro_rules! evaluate_expr {
($e:expr) => {
$e
};
}
fn main() {
let _ = evaluate_expr!(42 + 8);
let _ = evaluate_expr!("Hello".to_uppercase());
let _ = evaluate_expr!(vec![1, 2, 3].len());
let _ = evaluate_expr!(async { 100 });
}
ty
ty 用于匹配类型(Type),包括基本类型、复合类型、自定义类型、trait 对象等。
macro_rules! define_type_alias {
($name:ident, $target_type:ty) => {
type $name = $target_type;
};
}
define_type_alias!(Callback, fn(i32, i32) -> bool);
define_type_alias!(UserMap, std::collections::HashMap<String, Vec<u8>>);
define_type_alias!(BoxedError, Box<dyn std::error::Error>);
ident
ident 匹配标识符(Identifier),即变量名、函数名、类型名或模块名等。它也可以匹配原始标识符(Raw Identifier,如 r#type)。
macro_rules! create_variable {
($var_name:ident, $value:expr) => {
let $var_name = $value;
};
}
fn main() {
create_variable!(user_count, 100);
create_variable!(r#async, true);
println!("{} {}", user_count, r#async);
}
path
path 匹配类型或模块的路径(Path),例如 std::collections::HashMap 或 self::module::Type。
macro_rules! instantiate_from_path {
($type_path:path) => {
<$type_path>::new()
};
}
fn main() {
let _vec = instantiate_from_path!(std::vec::Vec::<i32>);
let _map = instantiate_from_path!(std::collections::HashMap::<String, i32>);
}
tt
tt 代表标记树(Token Tree)。它是宏系统中最基础的构建块,可以匹配单个标记(如标识符、字面量、标点符号)或由括号 ()、方括号 [] 或花括号 {} 包裹的标记组。
macro_rules! count_tokens {
($($tree:tt)*) => {
$(
println!("Token: {}", stringify!($tree));
)*
};
}
fn main() {
count_tokens!(a + b * (c - d));
}
上述代码会将 a, +, b, *, (c - d) 分别作为独立的标记树打印出来。
meta
meta 用于匹配属性(Attribute)的内部内容,即 #[...] 或 #![...] 括号内的元数据。
macro_rules! apply_attribute {
(#[$attr:meta]) => {
#[$attr]
struct Config;
};
}
apply_attribute!(#[derive(Debug, Default)]);
lifetime
lifetime 专门用于匹配生命周期参数,以单引号 ' 开头。
macro_rules! define_struct_with_lifetime {
($lt:lifetime) => {
struct DataRef<$lt> {
content: &$lt str,
}
};
}
define_struct_with_lifetime!('a);
vis
vis 匹配可见性修饰符(Visibility),如 pub、pub(crate)、pub(super) 等。如果没有可见性修饰符,它也可以匹配空内容。
macro_rules! declare_function {
($visibility:vis fn $name:ident()) => {
$visibility fn $name() {
println!("Function called");
}
};
}
declare_function!(pub fn public_api);
declare_function!(fn private_helper);
declare_function!(pub(crate) fn internal_api);
literal
literal 匹配字面量(Literal),包括整数、浮点数、字符、字符串和布尔值。
macro_rules! print_literal_info {
($val:literal) => {
println!("Literal value: {}", $val);
};
}
fn main() {
print_literal_info!(255);
print_literal_info!(3.14159);
print_literal_info!('R');
print_literal_info!("Rust");
print_literal_info!(true);
}