在单独的文件中定义宏。 例如,创建名为 mymacro.rs 的文件并定义宏:
#[macro_export] macro_rules! my_macro { () => { println!("Hello, world!"); }; } |
在要使用宏的文件中,使用 use 语句导入宏:
use mymacro::my_macro; |
然后,就可以在代码中使用宏了:
fn main() { my_macro!(); } |
注意,包含宏的文件必须位于单独的模块或板块中,而且必须使用 #[macro_export] 属性才能导入宏。
如何迭代宏的参数?
在 Rust 中,可以使用concat!宏和递归来迭代参数。以下是如何在宏中迭代参数的示例:
macro_rules! print_arguments { |
在这个示例中,print_arguments 宏接受数量可变的参数,并打印每个参数。 当只剩下一个参数时,宏使用模式匹配来匹配基本情况;当有多个参数时,宏使用递归情况来匹配。 模式中的 + 表示模式出现一次或多次。
运行上述代码时,将输出
1 |
宏内使用多个宏?
在 Rust 中,你可以在宏中使用多个宏,只需在外部宏中调用内部宏即可。以下是演示此操作的示例:
macro_rules! inner_macro1 { |
在上面的示例中,我们定义了两个内部宏 inner_macro1 和 inner_macro2,它们分别打印一条信息。 然后,我们定义了一个外部宏 outer_macro,用于调用这些内部宏。 最后,在主函数中,我们调用 outer_macro 运行两个内部宏。
运行这段代码时,您将看到以下输出:
Inner Macro 1 |
宏和函数有什么区别?
宏和函数都用于 Rust 中的代码重用,但有一些根本的区别。
- 语法:Rust 中的宏使用 macro_rules! 语法定义,而函数使用 fn 关键字。
- 参数:宏可以采用可变数量的参数并可以接受任何数据类型,而函数具有固定数量的参数并需要类型注释。
- 代码生成:宏允许程序员在编译时生成代码,并将其插入到程序中。另一方面,函数在运行时执行其代码,这可能会导致性能开销。
- 范围:宏在语法级别操作,可以直接操作源代码,而函数在语义级别操作,不能访问或修改源代码。
如何解析宏中的单个标记?
要解析 Rust 宏中的单个标记,可以使用以下步骤:
- 使用 macro_rules! 关键字定义自定义宏。
- 在宏定义中指定所需的输入标记。
- 使用
macro_rules! parse_token { |
在本例中,parse_token!宏定义了一个捕获单个标记($token:ident)的模式,然后使用 stringify! 当使用 parse_token!(value)调用 parse_token! 宏时,它会捕获值标记并打印其表示。
输出:Token: "value"
您可以添加更多模式来捕获不同类型的标记,或添加模式来捕获多个标记,从而扩展示例。
下面是一个高级示例,演示了如何在 Rust 宏中解析多个标记:
macro_rules! parse_tokens { |
在本例中,parse_tokens!宏匹配标识符令牌($token:ident)或非标识符令牌($token:tt)。 然后使用 stringify! 宏打印捕获标记的字符串表示。 在打印标记后,宏会递归调用自己 (parse_tokens!) 剩余的标记 ($($rest)*),直到不再有标记为止。
当使用 parse_tokens!(value1,value2, "string", (1, 2, 3), 3.14) 来调用 parse_tokens! 宏时,它会一次捕获并打印一个标记。
输出:
Token: "value1" |
注意:tt 标记树占位符(tree placeholder)可用于匹配任何有效标记,使宏可以处理各种标记类型。