跳到主要内容

宏(Macros)

宏(Macros)是 Rust 中的元编程工具,允许你编写生成其他代码的代码。宏在编译时展开,可以减少代码重复并提供强大的抽象能力。

声明式宏 (macro_rules!)

基本宏定义

macro_rules! say_hello {
() => {
println!("Hello, world!");
};
}

fn main() {
say_hello!();
}

带参数的宏

macro_rules! create_function {
($func_name:ident) => {
fn $func_name() {
println!("You called {:?}()", stringify!($func_name));
}
};
}

create_function!(foo);
create_function!(bar);

fn main() {
foo();
bar();
}

多种模式匹配

macro_rules! test {
// 无参数情况
() => {
println!("No arguments");
};

// 单个参数
($x:expr) => {
println!("One argument: {}", $x);
};

// 两个参数
($x:expr, $y:expr) => {
println!("Two arguments: {} and {}", $x, $y);
};

// 可变参数
($($x:expr),*) => {
$(
println!("Argument: {}", $x);
)*
};
}

fn main() {
test!();
test!(1);
test!(1, 2);
test!(1, 2, 3, 4);
}

宏的模式类型

表达式 (expr)

macro_rules! calculate {
($expr:expr) => {
{
let result = $expr;
println!("Expression: {} = {}", stringify!($expr), result);
result
}
};
}

fn main() {
let x = calculate!(2 + 3 * 4);
let y = calculate!(x * 2);
println!("Final result: {}", y);
}

标识符 (ident)

macro_rules! create_struct {
($name:ident, $($field:ident: $type:ty),*) => {
struct $name {
$(
$field: $type,
)*
}

impl $name {
fn new($($field: $type),*) -> Self {
$name {
$(
$field,
)*
}
}
}
};
}

create_struct!(Person, name: String, age: u32);

fn main() {
let person = Person::new("Alice".to_string(), 30);
println!("Name: {}, Age: {}", person.name, person.age);
}

类型 (ty)

macro_rules! impl_display {
($type:ty) => {
impl std::fmt::Display for $type {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
};
}

#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}

impl_display!(Point);

fn main() {
let point = Point { x: 1, y: 2 };
println!("Point: {}", point);
}

语句 (stmt) 和项目 (item)

macro_rules! create_module {
($mod_name:ident, $($item:item)*) => {
mod $mod_name {
$(
$item
)*
}
};
}

create_module!(my_module,
pub fn hello() {
println!("Hello from my_module!");
}

pub struct Data {
pub value: i32,
}

impl Data {
pub fn new(value: i32) -> Self {
Data { value }
}
}
);

fn main() {
my_module::hello();
let data = my_module::Data::new(42);
println!("Data value: {}", data.value);
}

重复模式

基本重复

macro_rules! vec_of_strings {
($($x:expr),*) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x.to_string());
)*
temp_vec
}
};
}

fn main() {
let v = vec_of_strings!["hello", "world", "rust"];
println!("{:?}", v);
}

嵌套重复

macro_rules! matrix {
($([$($x:expr),*]),*) => {
{
let mut matrix = Vec::new();
$(
let mut row = Vec::new();
$(
row.push($x);
)*
matrix.push(row);
)*
matrix
}
};
}

fn main() {
let m = matrix![
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];

for row in &m {
println!("{:?}", row);
}
}

实用宏示例

HashMap 创建宏

macro_rules! hashmap {
($($key:expr => $value:expr),* $(,)?) => {
{
let mut map = std::collections::HashMap::new();
$(
map.insert($key, $value);
)*
map
}
};
}

fn main() {
let map = hashmap! {
"name" => "Alice",
"age" => "30",
"city" => "New York",
};

for (key, value) in &map {
println!("{}: {}", key, value);
}
}

枚举生成宏

macro_rules! create_enum {
($name:ident { $($variant:ident),* }) => {
#[derive(Debug, PartialEq)]
enum $name {
$(
$variant,
)*
}

impl $name {
fn variants() -> Vec<&'static str> {
vec![
$(
stringify!($variant),
)*
]
}

fn from_str(s: &str) -> Option<Self> {
match s {
$(
stringify!($variant) => Some($name::$variant),
)*
_ => None,
}
}
}
};
}

create_enum!(Color { Red, Green, Blue });

fn main() {
println!("Color variants: {:?}", Color::variants());

if let Some(color) = Color::from_str("Red") {
println!("Parsed color: {:?}", color);
}
}

测试宏

macro_rules! test_case {
($name:ident: $input:expr => $expected:expr) => {
#[test]
fn $name() {
assert_eq!($input, $expected);
}
};
}

fn add(a: i32, b: i32) -> i32 {
a + b
}

test_case!(test_add_positive: add(2, 3) => 5);
test_case!(test_add_negative: add(-1, 1) => 0);
test_case!(test_add_zero: add(0, 0) => 0);

fn main() {
println!("Tests defined with macro");
}

过程宏 (Procedural Macros)

过程宏是更高级的宏形式,需要单独的 crate。这里展示基本概念:

派生宏示例

// 这需要在单独的 proc-macro crate 中定义
/*
use proc_macro::TokenStream;
use quote::quote;
use syn;

#[proc_macro_derive(HelloMacro)]
pub fn hello_macro_derive(input: TokenStream) -> TokenStream {
let ast = syn::parse(input).unwrap();
impl_hello_macro(&ast)
}

fn impl_hello_macro(ast: &syn::DeriveInput) -> TokenStream {
let name = &ast.ident;
let gen = quote! {
impl HelloMacro for #name {
fn hello_macro() {
println!("Hello, Macro! My name is {}!", stringify!(#name));
}
}
};
gen.into()
}
*/

// 使用示例
trait HelloMacro {
fn hello_macro();
}

// #[derive(HelloMacro)]
struct Pancakes;

// 手动实现(模拟派生宏的效果)
impl HelloMacro for Pancakes {
fn hello_macro() {
println!("Hello, Macro! My name is Pancakes!");
}
}

fn main() {
Pancakes::hello_macro();
}

高级宏技巧

宏中的宏

macro_rules! impl_ops {
($type:ty, $($op:ident),*) => {
$(
impl_op!($type, $op);
)*
};
}

macro_rules! impl_op {
($type:ty, add) => {
impl std::ops::Add for $type {
type Output = Self;
fn add(self, other: Self) -> Self {
Self(self.0 + other.0)
}
}
};
($type:ty, sub) => {
impl std::ops::Sub for $type {
type Output = Self;
fn sub(self, other: Self) -> Self {
Self(self.0 - other.0)
}
}
};
}

#[derive(Debug, Clone, Copy)]
struct Number(i32);

impl_ops!(Number, add, sub);

fn main() {
let a = Number(10);
let b = Number(5);

println!("a + b = {:?}", a + b);
println!("a - b = {:?}", a - b);
}

条件编译宏

macro_rules! debug_print {
($($arg:tt)*) => {
#[cfg(debug_assertions)]
{
println!("[DEBUG] {}", format!($($arg)*));
}
};
}

macro_rules! feature_gate {
($feature:literal, $($item:item)*) => {
$(
#[cfg(feature = $feature)]
$item
)*
};
}

feature_gate!("advanced",
fn advanced_function() {
println!("This is an advanced function!");
}
);

fn main() {
debug_print!("This is a debug message: {}", 42);

#[cfg(feature = "advanced")]
advanced_function();

#[cfg(not(feature = "advanced"))]
println!("Advanced feature not enabled");
}

实际应用示例

配置宏

macro_rules! config {
(
$(
$key:ident: $type:ty = $default:expr
),* $(,)?
) => {
#[derive(Debug)]
struct Config {
$(
pub $key: $type,
)*
}

impl Default for Config {
fn default() -> Self {
Config {
$(
$key: $default,
)*
}
}
}

impl Config {
$(
paste::paste! {
pub fn [<set_ $key>](mut self, value: $type) -> Self {
self.$key = value;
self
}

pub fn [<get_ $key>](&self) -> &$type {
&self.$key
}
}
)*
}
};
}

// 注意:这个示例需要 paste crate,这里简化实现
macro_rules! simple_config {
(
$(
$key:ident: $type:ty = $default:expr
),* $(,)?
) => {
#[derive(Debug)]
struct Config {
$(
pub $key: $type,
)*
}

impl Default for Config {
fn default() -> Self {
Config {
$(
$key: $default,
)*
}
}
}
};
}

simple_config! {
host: String = "localhost".to_string(),
port: u16 = 8080,
debug: bool = false,
timeout: u64 = 30,
}

fn main() {
let config = Config::default();
println!("Default config: {:?}", config);

let custom_config = Config {
host: "example.com".to_string(),
port: 3000,
debug: true,
timeout: 60,
};
println!("Custom config: {:?}", custom_config);
}

状态机宏

macro_rules! state_machine {
(
$name:ident {
states: [$($state:ident),*],
events: [$($event:ident),*],
transitions: {
$(
$from:ident + $evt:ident => $to:ident
),*
}
}
) => {
#[derive(Debug, Clone, Copy, PartialEq)]
enum State {
$(
$state,
)*
}

#[derive(Debug, Clone, Copy, PartialEq)]
enum Event {
$(
$event,
)*
}

#[derive(Debug)]
struct $name {
current_state: State,
}

impl $name {
fn new(initial_state: State) -> Self {
$name {
current_state: initial_state,
}
}

fn current_state(&self) -> State {
self.current_state
}

fn handle_event(&mut self, event: Event) -> Result<State, String> {
let new_state = match (self.current_state, event) {
$(
(State::$from, Event::$evt) => State::$to,
)*
_ => return Err(format!(
"Invalid transition from {:?} with event {:?}",
self.current_state, event
)),
};

self.current_state = new_state;
Ok(new_state)
}
}
};
}

state_machine! {
TrafficLight {
states: [Red, Yellow, Green],
events: [Timer, Emergency],
transitions: {
Red + Timer => Green,
Green + Timer => Yellow,
Yellow + Timer => Red,
Red + Emergency => Yellow,
Green + Emergency => Yellow,
Yellow + Emergency => Red
}
}
}

fn main() {
let mut light = TrafficLight::new(State::Red);
println!("Initial state: {:?}", light.current_state());

match light.handle_event(Event::Timer) {
Ok(new_state) => println!("Transitioned to: {:?}", new_state),
Err(e) => println!("Error: {}", e),
}

match light.handle_event(Event::Emergency) {
Ok(new_state) => println!("Emergency transition to: {:?}", new_state),
Err(e) => println!("Error: {}", e),
}
}

最佳实践

  1. 保持宏简单:复杂的逻辑应该在函数中实现
  2. 提供良好的错误信息:使用 compile_error!
  3. 文档化宏:解释宏的用途和用法
  4. 测试宏:确保宏在各种情况下都能正确工作
  5. 避免过度使用:宏应该是最后的选择
macro_rules! assert_type {
($expr:expr, $type:ty) => {
{
fn type_check(_: $type) {}
type_check($expr);
$expr
}
};
}

macro_rules! compile_time_assert {
($condition:expr) => {
const _: () = {
if !$condition {
panic!("Compile-time assertion failed");
}
};
};
}

fn main() {
let x = 42;
let checked_x = assert_type!(x, i32);
println!("Checked value: {}", checked_x);

compile_time_assert!(std::mem::size_of::<i32>() == 4);
println!("Compile-time assertion passed");
}

宏是 Rust 中强大的元编程工具,可以减少代码重复并提供灵活的抽象。但应该谨慎使用,确保代码的可读性和可维护性。