macro_rules! 宏规则
Rust提供了一个强大的宏系统,允许元编程。 宏看起来像函数,但它们的名称都以感叹号 !
结尾。
// 定义一个名为 `print_message` 的宏
macro_rules! print_message {
// 此模式匹配简单消息并打印它
// `($message:expr)` 表示宏接受一个表达式参数。
($message:expr) => {
// 该宏会将此块的内容替换到宏调用处。
println!("Message: {}", $message);
};
}
fn main() {
// 使用自定义宏打印简单消息
print_message!("Hello, Rust!");
// Message: Hello, Rust!
}
语法
Designators (指示符)
宏的参数以美元符号 $
开头,并使用指示符进行类型注解。
这是一些可用指示符的示例:
block
表示块expr
表示表达式ident
表示标识符(变量/函数名)literal
表示字面常量stmt
表示语句
macro_rules! print_result {
// 此宏接受类型为 `expr` 的表达式并将其作为字符串与其结果一起打印出来。
// 使用 `expr` 指示符表示表达式。
($expression:expr) => {
// `stringify!` 将表达式按原样转换为字符串。
println!("{:?} = {:?}",
stringify!($expression),
$expression);
};
}
fn main() {
print_result!(58u32 + 58);
// "58u32 + 58" = 116
print_result!({
let x = 27u32;
x * x - 1
});
// "{ let x = 27u32; x * x - 1 }" = 728
}
可以在 Rust参考手册
中了解更多关于指示符的信息。
重载
宏可以被重载,以接受不同的参数组合。
macro_rules! print_message {
// 此模式匹配简单消息并打印它
($message:expr) => {
println!("Message: {}", $message);
};
// 重载!
// 此模式匹配具有 format 格式字符串及其参数的消息并打印它
($format:expr, $($arg:expr),*) => {
println!($format, $($arg),*);
};
}
fn main() {
// 使用自定义宏打印简单消息
print_message!("Hello, Rust!");
// Message: Hello, Rust!
// 使用带有格式字符串和参数的自定义宏
print_message!("{} + {} = {}", 2, 3, 2 + 3);
// 2 + 3 = 5
}
重复
宏可以在参数列表中使用 +
表示一个参数可重复一次或多次,或 *
表示参数可以出现任意次。
因此,在上面示例中的匹配器 $($arg:expr),*
意味着它将匹配任意个由逗号分隔的表达式。
DSL
DSL = 领域特定语言
DSL 是嵌入在 Rust 宏中的迷你"语言"。它属于完全合法的真 Rust,因为宏系统会将其展开为正常的 Rust 结构,但它直观看起来就像一种小语言。
macro_rules! calculate {
(eval $e:expr) => {
{
let val: usize = $e;
// `stringify!` 将表达式按原样转换为字符串。
println!("{} = {}", stringify!{$e}, val);
}
};
}
fn main() {
calculate! {
eval 5 + 8 // `eval` 不是 Rust 关键字,但它看起来像是!这就是"DSL"。
}
// 5 + 8 = 13
calculate! {
eval (5 + 8) * (8 / 5)
}
// (5 + 8) * (8 / 5) = 13
}
变参
变参 接口接受任意数量的参数。
// 定义一个名为 `print_args` 的变参宏
macro_rules! print_args {
// 基本 case:没有参数
() => {};
// 递归 case:打印第一个参数,并为剩余参数再次调用宏
($first:expr $(, $rest:expr)*) => {
println!("Argument: {}", $first);
print_args!($($rest),*);
};
}
fn main() {
// 使用不同数量的参数使用变参宏
print_args!();
// No output
print_args!(1);
// Argument: 1
print_args!(10, "literank", 3.14);
// Argument: 10, Argument: literank, Argument: 3.14
}
代码挑战
尝试修改编辑器中提供的宏以获取正确的答案。
Loading...
> 此处输出代码运行结果