| name | rust-macros |
| description | Rust 宏技能。提供 Rust 宏的完整参考,包括声明宏、过程宏、宏规则等。TRIGGER when: 用户编写宏、使用宏、调试宏、或需要了解宏系统时触发。SKIP: 非宏相关的 Rust 开发。 |
Rust 宏技能
本技能提供 Rust 宏的完整参考,包括声明宏、过程宏、宏规则等。
触发条件
当用户执行以下操作时触发此技能:
跳过条件
以下情况不触发此技能:
声明宏
基本语法
macro_rules! say_hello {
() => {
println!("Hello!");
};
}
say_hello!();
参数匹配
macro_rules! create_function {
($func_name:ident) => {
fn $func_name() {
println!("函数 {} 被调用", stringify!($func_name));
}
};
}
create_function!(foo);
create_function!(bar);
fn main() {
foo();
bar();
}
表达式匹配
macro_rules! calculate {
($a:expr, $b:expr, $op:expr) => {
match $op {
"+" => $a + $b,
"-" => $a - $b,
"*" => $a * $b,
"/" => $a / $b,
_ => panic!("未知运算符"),
}
};
}
fn main() {
let result = calculate!(10, 5, "+");
println!("10 + 5 = {}", result);
}
重复模式
macro_rules! vec {
($($x:expr),*) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x);
)*
temp_vec
}
};
($($x:expr),+ $(,)?) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x);
)*
temp_vec
}
};
}
fn main() {
let v = vec![1, 2, 3];
let v = vec![1, 2, 3,];
}
多分支宏
macro_rules! my_macro {
() => {
println!("无参数");
};
($x:expr) => {
println!("一个参数: {}", $x);
};
($x:expr, $y:expr) => {
println!("两个参数: {} 和 {}", $x, $y);
};
($($x:expr),+) => {
$(
println!("参数: {}", $x);
)+
};
}
fn main() {
my_macro!();
my_macro!(42);
my_macro!(1, 2);
my_macro!(1, 2, 3, 4, 5);
}
过程宏
派生宏
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
#[proc_macro_derive(MyMacro)]
pub fn my_macro_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = &input.ident;
let expanded = quote! {
impl MyTrait for #name {
fn my_method(&self) -> String {
format!("{} 实现了 MyTrait", stringify!(#name))
}
}
};
TokenStream::from(expanded)
}
属性宏
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, ItemFn};
#[proc_macro_attribute]
pub fn my_attribute(args: TokenStream, input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as ItemFn);
let name = &input.sig.ident;
let block = &input.block;
let expanded = quote! {
fn #name() {
println!("函数 {} 被调用", stringify!(#name));
#block
}
};
TokenStream::from(expanded)
}
函数式宏
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, LitStr};
#[proc_macro]
pub fn my_macro(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as LitStr);
let value = input.value();
let expanded = quote! {
println!("宏输出: {}", #value);
};
TokenStream::from(expanded)
}
宏规则
匹配器
macro_rules! matchers {
($i:ident) => { stringify!($i) };
($e:expr) => { $e };
($t:ty) => { stringify!($t) };
($l:literal) => { $l };
($p:pat) => { stringify!($p) };
($s:stmt) => { stringify!($s) };
($b:block) => { stringify!($b) };
($i:item) => { stringify!($i) };
($m:meta) => { stringify!($m) };
($l:lifetime) => { stringify!($l) };
($t:tt) => { stringify!($t) };
}
重复操作符
macro_rules! repeat {
($($x:expr),*) => {
vec![$($x),*]
};
($($x:expr),+) => {
vec![$($x),+]
};
($x:expr $(, $y:expr)?) => {
($x, $($y)?)
};
}
宏导出
#[macro_export]
macro_rules! my_macro {
() => {
println!("导出的宏");
};
}
内置宏
调试宏
println!("Hello, {}!", "world");
println!("{:?}", vec![1, 2, 3]);
println!("{:#?}", vec![1, 2, 3]);
eprintln!("错误: {}", "文件未找到");
let x = 5;
let y = dbg!(x * 2);
fn not_implemented() -> i32 {
todo!("这个函数还没实现");
}
fn not_implemented() -> i32 {
unimplemented!();
}
fn unreachable() {
unreachable!("不应该到达这里");
}
panic!("发生错误");
panic!("错误: {}", "文件未找到");
类型宏
let s = stringify!(hello world);
let s = concat!("Hello", ", ", "world!",);
let name = stringify!(my_function);
println!("文件: {}", file!());
println!("行号: {}", line!());
println!("列号: {}", column!());
println!("模块路径: {}", module_path!());
编译宏
if cfg!(target_os = "linux") {
println!("Linux 平台");
}
let version = env!("CARGO_PKG_VERSION");
let debug = option_env!("DEBUG");
let content = include_str!("data.txt");
let data = include_bytes!("data.bin");
#[cfg(not(target_os = "linux"))]
compile_error!("这个库只支持 Linux");
宏最佳实践
- 命名规范:使用下划线命名宏
- 导出宏:使用
#[macro_export]
- 文档注释:为宏添加文档
- 测试宏:编写测试确保宏正确工作
- 调试宏:使用
cargo expand 查看宏展开
常见陷阱
- 卫生性:宏中的变量不会污染外部作用域
- 重复匹配:注意重复模式的匹配规则
- 优先级:宏展开可能影响运算符优先级
- 错误信息:宏错误可能难以调试
- 性能:宏可能增加编译时间
调试宏
cargo expand
cargo install cargo-expand
cargo expand
cargo expand my_module
编译器调试
RUSTFLAGS=-Zmacro-backtrace cargo build
macro_rules! debug_macro {
($($tt:tt)*) => {
eprintln!("宏输入: {}", stringify!($($tt)*));
$($tt)*
};
}