Rust宏
- 宏的基本概念:Rust中的宏是一种元编程工具,允许编写生成更多代码的代码,常用于简化重复模式,如
println!
、vec!
和panic!
。 - 创建和使用宏:使用
macro_rules!
宏创建新宏,定义具体规则和模式。例如,创建无参数的宏hello_world
,用于 生成特定输出。 - 宏的参数和重复:宏可以接受参数并根据输入定制生成代码,如
print_message
宏。使用$(...)*
语法在宏中生成重复代码,灵活处理多个输入。
Rust 中的宏是一段生成另一段代码的代码。
宏根据输入生成代码,简化重复模式,并使代码更简洁。
Rust 宏简单地让我们编写生成更多代码的代码,这也被称为元编程。宏在 Rust 中被广泛使用。
一些流行的 Rust 宏包括 println!
、vec!
和 panic!
。
在 Rust 中创建宏
我们可以使用 macro_rules!
宏来创建宏。或许令人惊讶的是,我们确实使用一个宏来创建宏。
macro_rules!
宏有一个特殊的语法。
macro_rules! macro_name {
(...) => {...}
// 更多匹配规则
}
这里,() => {}
是宏规则的条目。我们可以在一个宏中匹配许多规则。
让我们看一个简单的宏示例,它定义了一个新函数来打印 “Hello, World!”。
// 一个名为 `hello_world` 的简单宏
macro_rules! hello_world {
// `()` 表示宏不接受参数
() => {
// 宏将展开为这个块的内容
println!("Hello, World!")
};
}
fn main() {
// 调用 hello_world 宏
// 这个调用将展开为 `println!("Hello, World!");`
hello_world!()
}
输出
Hello, World!
在这个示例中,我们创建了一个名为 hello_world
的宏。宏定义有一个匹配规则:
() => {
println!("Hello, World!");
};
要调用宏,我们在 main()
函数中使用 hello_world!()
调用。
宏会将 hello_world!()
调用替换为宏定义中的代码,即 println!("Hello, World!")
。
在 Rust 中创建带参数的宏
宏也可以接受参数,这允许我们根据不同的输入定制它生成的代码。
例如,这里有一个定义打印自定义消息的函数的宏:
// 一个名为 `print_message` 的宏
macro_rules! print_message {
// 接受一个参数表达式的匹配规则
($message:expr) => {
println!("{}", $message)
};
}
fn main() {
// 使用参数调用宏
print_message!("I am learning Rust!");
}
输出
我正在学习 Rust!
这里,我们创建了一个名为 print_message
的宏,它接受一个参数 $message
。宏的参数以美元符号 $
开头,并使用指示器进行类型注解。
Rust 会尝试匹配定义在匹配规则中的模式。在上面的例子中,我们的规则是:
($message:expr) => {
println!("{}", $message)
};
美元符号 $
后的第一部分是变量的名称。我们将其捕获为 $message
。
分号 :
之后的部分称为指示器,它们是我们可以选择匹配的类型。在这个示例中,我们使用的是表达式指示器(expr
)。
现在,当我们调用宏 print_message!("我正在学习 Rust!")
时,它会匹配我们的输入表达式并捕获 $message
变量。
这里,$message
被赋值为 "我正在学习 Rust!"
,然后传递给 println!("{}", $message)
。
它会生成等同于写 println!("{}", "我正在学习 Rust!")
的代码。$message
参数允许我们指定要打印的消息。
注意:在宏规则体内我们可以使用许多指示器:
stmt
:一条语句pat
:一个模式expr
:一个表达式ty
:一个类型ident
:一个标识符…
Rust 中的宏重复
Rust 宏在我们需要生成重复代码时也很有用。我们可以定义一个宏来接受参数,并根据这些参数重复生成代码。
macro_rules!
宏通过 $(...)*
语法支持重复。括号内的 ...
可以是任何有效的 Rust 表达式或模式。
以下是演示宏重复的示例:
// 一个使用重复的宏
macro_rules! repeat_print {
// 匹配规则,匹配参数中的多个表达式
($($x:expr),*) => {
$(
println!("{}", $x);
)*
};
}
fn main() {
// 使用多个参数调用宏
repeat_print!(1, 2, 3);
}
输出
1
2
3
这里,宏 repeat_print
接受单个参数 ($($x:expr),*)
,这是一个重复模式。
模式由零个或多个用逗号分隔的表达式组成,由宏匹配。结尾的星号(*
)将反复匹配 $()
内的模式。
花括号内的代码 println!("{}", $x);
,被零次或多次重复,对于宏定义体内 $(...)*
包围的参数列表中的每个表达式都执行一次。代码中的 $x
指的是匹配的表达式。
生成的代码的每次迭代都将打印不同的表达式。现在,当我们调用 repeat_print!(1, 2, 3);
时,宏将生成以下代码:
println!("{}", 1); // 匹配参数 1,
println!("{}", 2); // 匹配参数 2,
println!("{}", 3); // 匹配参数 3
因此,这个宏 repeat_print!
可以以简洁便利的方式打印多个表达式,无需每次都写出 println!
宏。