Rust
中的宏是生成另一段代码的一段代码。可以根据输入生成代码,简化重复模式,使得代码更加简洁。比如我们一直在用的println!,vec!,panic!
都是宏。
创建宏
可以使用macro_rules!
创建一个宏:
macro_rules! macro_name {(...) => {...}
}
这里的
() => {}
是宏规则条目,我们可以在单个宏中匹配很多规则。
下面的宏将实现打印一个Hello World!
:
macro_rules! hello_world {() => {println!("hello world!");};
}fn main() {hello_world!()
}
带参数的宏
宏也可以接受参数,这使我们能够根据不同的输入定制生成的代码。例如,这是一个定义函数以打印自定义消息的宏:
macro_rules! print_msg {($message:expr) => {println!("{}", $message)};
}fn main() {print_msg!("helllo Rust");
}
在这里,创建了一个名为 print_message
的宏,它接受一个参数 $message。宏的参数使用美元符号 $ 进行前缀,并用设计器进行类型注释。Rust
将尝试匹配在匹配规则中定义的模式。在上面的例子中,我们的规则是:
($message:expr) => {println!("{}", $message)
};
在分号后面的部分:被称为标识符,这些是我们可以选择匹配的类型。在示例中,我们使用表达式标识符(expr
)。
在这个例子中 m e s s a g e message message被赋值为hello Rust
,然后传递到println!({},$message)
;
注意:在宏规则体内,我们可以使用许多设计
ators
:
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, 4, 5, 6);
}
在这里,宏
repeat_print
接受一个参数,($($x:expr),*)
,这是一个重复的模式。
该模式由零个或多个表达式组成,用逗号分隔,这些表达式由宏匹配。在末尾的星号( * )
符号将反复匹配$()
中的模式。
- 在大括号内的代码 println!({}, $x); ,根据宏定义的主体中 $(…)* 的包装,会重复零次或多次,每次对参数列表中的表达式执行一次。
- 代码中的
$x
指的是匹配的表达式。 生成的代码的每次迭代都将打印不同的表达式。 - 现在,当我们调用 repeat_print!(1, 2, 3); 时,宏将生成这段代码:
println!("{}", 1); // matches argument 1,
println!("{}", 2); // matches argument 2,
println!("{}", 3); // matches argument 3
因此,这个宏 repeat_print! 能够以简洁和便捷的方式打印多个表达式,而无需每次都编写println!
宏。