前置知识点
各种宏
- 宏定义:
使用 macro_rules! 关键词来定义宏,这是一种模式匹配式的宏定义方式。
自 Rust 1.26 版本开始,可以使用 proc_macro 属性宏来定义过程宏(如 derive 宏)。
- 宏的使用:
宏可以通过定义好的宏名来调用,宏调用时传入的参数会被宏定义中的模式匹配所捕获,并根据定义的规则生成相应的代码。
- 卫生宏(hygiene):
Rust 的宏支持卫生性,这意味着宏调用时的上下文信息会被保留下来,以避免命名冲突等问题。
- 模式匹配:
Rust 的宏支持模式匹配,这使得宏可以根据传入的不同参数生成不同的代码。
- 过程宏(procedural macros):
Rust 支持三种类型的过程宏:derive 宏、属性宏(attribute-like macros)和函数宏(function-like macros)。
- derive 宏允许用户为自定义类型添加默认的行为。
- 属性宏和函数宏允许用户定义更加复杂的代码生成逻辑。
- 宏的可见性和导入:
宏可以通过 pub use 语句来导入到其他模块中。
在 Rust 2018 版本之前,需要使用 #[macro_use] 来导入宏。但在 Rust 2018 版本之后,可以直接通过 use 语句来导入宏。
和函数的区别
在Rust中,宏定义(macros)和函数(functions)有以下区别:
-
语法:宏定义采用
macro_rules!
关键字进行定义,而函数使用fn
关键字进行定义。 -
调用方式:宏定义使用
!
运算符来调用,而函数使用圆括号()
运算符来调用。 -
参数传递:宏定义可以接受任意数量的参数,并且可以使用模式匹配来匹配传递的参数,而函数需要明确指定参数的数量和类型。
-
代码生成:宏定义在编译期间进行代码生成,将宏展开为实际的代码,而函数在运行时执行。
-
功能扩展:宏定义可以执行复杂的代码转换和代码生成,可以在编译期间进行元编程,而函数只能执行预定义的操作。
总的来说,宏定义在编译期间进行代码生成和转换,具有更高的灵活性和功能扩展性,但也更加复杂和难以理解。函数则是在运行时执行,更加简单和直观。在选择宏定义和函数之间,需要根据具体的需求和场景来决定。
练习题
macros1
题目
考点:注意宏需要用!
来定义。
rust
// macros1.rs
//
// Execute `rustlings hint macros1` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
macro_rules! my_macro {
() => {
println!("Check out my macro!");
};
}
fn main() {
my_macro();
}
题解
rust
macro_rules! my_macro {
() => {
println!("Check out my macro!");
};
}
fn main() {
my_macro!();
}
macros2
题目
在宏的定义中使用了
rust
// macros3.rs
//
// Make me compile, without taking the macro out of the module!
//
// Execute `rustlings hint macros3` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
mod macros {
macro_rules! my_macro {
() => {
println!("Check out my macro!");
};
}
}
fn main() {
my_macro!();
}
题解
在 Rust 2018 之前,对于不在同一个直接 mod 下的 macro,都需要加 #[macro_use]
后才能使用。
rust
#[macro_use]
mod macros {
macro_rules! my_macro {
() => {
println!("Check out my macro!");
};
}
}
fn main() {
my_macro!();
}
marcros3
题目
rust
// macros4.rs
//
// Execute `rustlings hint macros4` or use the `hint` watch subcommand for a
// hint.
// I AM NOT DONE
#[rustfmt::skip]
macro_rules! my_macro {
() => {
println!("Check out my macro!");
}
($val:expr) => {
println!("Look at this other macro: {}", $val);
}
}
fn main() {
my_macro!();
my_macro!(7777);
}
题解
其实就是考察宏可以重载:
rust
// macros4.rs
//
// Execute `rustlings hint macros4` or use the `hint` watch subcommand for a
// hint.
#[rustfmt::skip]
macro_rules! my_macro {
() => {
println!("Check out my macro!");
};
($val:expr) => {
println!("Look at this other macro: {}", $val);
}
}
fn main() {
// 类似于一种重载
my_macro!();
my_macro!(7777);
}