当前位置:首页 > 技术 > 正文内容

Rust 声明式宏元变量(Fragment Specifiers)深度解析

访客 技术 2026年5月25日 3

item

在 Rust 中,item 代表 crate 中的一个顶层组件,例如模块、函数、结构体、枚举、常量、trait 等。可以将 crate 视为一个包含多个 item 的集合。

macro_rules! define_item {
    ($component:item) => {
        $component
    };
}

define_item!(
    #[derive(Debug, Clone)]
    struct NetworkConfig {
        ip: String,
        port: u16,
    }
);

define_item!(
    fn calculate_sum(a: i32, b: i32) -> i32 {
        a + b
    }
);

define_item!(
    mod network_utils {}
);

fn main() {
    let config = NetworkConfig { ip: "127.0.0.1".into(), port: 8080 };
    println!("{:?}", config);
    println!("Sum: {}", calculate_sum(10, 20));
}

block

block 匹配一个由花括号 {} 包裹的匿名命名空间作用域,内部可以包含多条语句和最终的表达式。

macro_rules! execute_block {
    ($body:block) => {
        $body
    };
}

fn main() {
    let result = execute_block!({
        let x = 10;
        let y = 20;
        x * y
    });
    println!("Result: {}", result);
}

stmt

stmt 用于匹配语句(Statement)。它可以是 itemlet 绑定、表达式语句或宏调用。需要注意的是,语句在宏匹配时通常不包含尾随的分号。

macro_rules! process_stmt {
    ($statement:stmt) => {
        $statement
    };
}

fn main() {
    // let 绑定
    process_stmt!(let max_retries = 5);
    
    // item
    process_stmt!(struct RetryConfig { delay: u64 });
    
    // 表达式语句
    process_stmt!(
        if max_retries > 0 {
            println!("Retrying...");
        }
    );
    
    // 宏调用
    process_stmt!(println!("Statement processed"));
}

pat_param

pat_param 用于匹配模式(Pattern),常用于 match 表达式或 if let 的左侧。与 pat 不同,pat_param 默认不支持 or-pattern(即使用 | 分隔的多个模式)。

macro_rules! check_pattern_param {
    ($p:pat_param) => {
        $p
    };
}

enum Status {
    Active,
    Inactive,
    Pending(u32),
}

fn main() {
    let status = Status::Pending(42);
    
    if let check_pattern_param!(Status::Pending(code)) = status {
        println!("Pending with code: {}", code);
    }
}

pat

pat 同样用于匹配模式,但它支持更广泛的模式类型,包括 or-pattern(例如 A | B)。

macro_rules! match_complex_pattern {
    ($pattern:pat) => {
        $pattern
    };
}

fn main() {
    let value = 2;
    match value {
        match_complex_pattern!(0 | 1 | 2) => println!("Low value"),
        _ => println!("High value"),
    }
}

expr

expr 匹配任何合法的 Rust 表达式(Expression),包括字面量、路径、运算符表达式、函数调用、闭包、控制流表达式等。

macro_rules! evaluate_expr {
    ($e:expr) => {
        $e
    };
}

fn main() {
    let _ = evaluate_expr!(42 + 8);
    let _ = evaluate_expr!("Hello".to_uppercase());
    let _ = evaluate_expr!(vec![1, 2, 3].len());
    let _ = evaluate_expr!(async { 100 });
}

ty

ty 用于匹配类型(Type),包括基本类型、复合类型、自定义类型、trait 对象等。

macro_rules! define_type_alias {
    ($name:ident, $target_type:ty) => {
        type $name = $target_type;
    };
}

define_type_alias!(Callback, fn(i32, i32) -> bool);
define_type_alias!(UserMap, std::collections::HashMap<String, Vec<u8>>);
define_type_alias!(BoxedError, Box<dyn std::error::Error>);

ident

ident 匹配标识符(Identifier),即变量名、函数名、类型名或模块名等。它也可以匹配原始标识符(Raw Identifier,如 r#type)。

macro_rules! create_variable {
    ($var_name:ident, $value:expr) => {
        let $var_name = $value;
    };
}

fn main() {
    create_variable!(user_count, 100);
    create_variable!(r#async, true);
    println!("{} {}", user_count, r#async);
}

path

path 匹配类型或模块的路径(Path),例如 std::collections::HashMapself::module::Type

macro_rules! instantiate_from_path {
    ($type_path:path) => {
        <$type_path>::new()
    };
}

fn main() {
    let _vec = instantiate_from_path!(std::vec::Vec::<i32>);
    let _map = instantiate_from_path!(std::collections::HashMap::<String, i32>);
}

tt

tt 代表标记树(Token Tree)。它是宏系统中最基础的构建块,可以匹配单个标记(如标识符、字面量、标点符号)或由括号 ()、方括号 [] 或花括号 {} 包裹的标记组。

macro_rules! count_tokens {
    ($($tree:tt)*) => {
        $(
            println!("Token: {}", stringify!($tree));
        )*
    };
}

fn main() {
    count_tokens!(a + b * (c - d));
}

上述代码会将 a, +, b, *, (c - d) 分别作为独立的标记树打印出来。

meta

meta 用于匹配属性(Attribute)的内部内容,即 #[...]#![...] 括号内的元数据。

macro_rules! apply_attribute {
    (#[$attr:meta]) => {
        #[$attr]
        struct Config;
    };
}

apply_attribute!(#[derive(Debug, Default)]);

lifetime

lifetime 专门用于匹配生命周期参数,以单引号 ' 开头。

macro_rules! define_struct_with_lifetime {
    ($lt:lifetime) => {
        struct DataRef<$lt> {
            content: &$lt str,
        }
    };
}

define_struct_with_lifetime!('a);

vis

vis 匹配可见性修饰符(Visibility),如 pubpub(crate)pub(super) 等。如果没有可见性修饰符,它也可以匹配空内容。

macro_rules! declare_function {
    ($visibility:vis fn $name:ident()) => {
        $visibility fn $name() {
            println!("Function called");
        }
    };
}

declare_function!(pub fn public_api);
declare_function!(fn private_helper);
declare_function!(pub(crate) fn internal_api);

literal

literal 匹配字面量(Literal),包括整数、浮点数、字符、字符串和布尔值。

macro_rules! print_literal_info {
    ($val:literal) => {
        println!("Literal value: {}", $val);
    };
}

fn main() {
    print_literal_info!(255);
    print_literal_info!(3.14159);
    print_literal_info!('R');
    print_literal_info!("Rust");
    print_literal_info!(true);
}

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。