声明宏

分类符

  • item 只匹配Rustitem的定义, 不会匹配指向item的标识符.
  • block 匹配blok表达式.
  • stmt 匹配语句. 除非item语句要求结尾有分号, 否则不会匹配语句最后的分号.
  • pat_param 允许跟在后面, 2021 editing开始.
  • pat 匹配任何形式的模式.
  • expr 匹配任何形式的表达式.
  • ty 匹配任何形式的类型表达式.
  • ident 匹配任何形式的标识符或者关键字.
  • path 匹配类型中的路径
  • tt 匹配标记树TokenTree.
  • meta 匹配属性. 准确的说是属性里面的内容.
  • lifetime 匹配生命周期注解或者标签. 和ident很像, 但是lifetime会匹配到前缀'.
  • vis 匹配可能为空的内容.
  • literal 匹配字面表达式.

item

item分类器只匹配Rustitem的定义, 不匹配指向item的标识符.

macro_rules! items {
    ($($item: item)*) => {};
}
items!{
    struct Foo;
    enum Bar {
        Baz
    }
    impl Foo {}
}
fn main() {}

item是在编译器完全确定的, 通常在程序执行期间保持固定, 并且可以驻留在支付存储器中.

  • modules
  • extern crate
  • use
  • function
  • type
  • struce
  • enum
  • union
  • constant
  • static
  • trait
  • impl
  • extern

block

block匹配bolck表达式

块(block)由{开始, 接着是一些语句, 最后以}结束. 块的类型要么是最后的值表达式类型, 要么是单元元组()类型.

macro_rules! blocks {
    ($($block: block)*) => {};
}
blocks! {
    {}
    { let abc; }
    {8}
}
fn main() {}

stmt

stmt匹配语句. 除非item语句要求结尾有分号, 否则不会匹配语句最后的分号.

item语句要求结尾有分号: 例如 单元结构体是一个例子, 定义中必须要带上结尾的分号.

macro_rules! statements {
    ($($stmt: stmt)*) => {$($stmt)*};
}
fn main() {
    statements!{
        struct Foo;
        fn foo() {}
        let bar = 8
        let bar = 8
        ;
        8;
        ;
        if true {} else {}
        {}
        ()
    }
}

pat_param

从 2021 edition 起,or-patterns模式开始应用,这让pat分类符不再允许跟随|

为了避免这个问题或者说恢复旧的 pat 分类符行为,你可以使用 pat_param 片段,它允许 | 跟在它后面,因为 pat_param 不允许 top levelor-patterns

macro_rules! patterns {
    (pat: $pat: pat) => {
        println!("pat: {}", stringify!($pat));
    };
    (pat_param: $($pat: pat_param)|*) => {
        $( println!("pat_param: {}", stringify!($pat)); )+
    };
}
fn main() {
    patterns!{
        pat: 0 | 1 | 2 | 3
    }
    patterns!{
        pat_param: 0 | 1 | 2 | 3
    }
}
macro_rules! patterns {
    ($($($pat: pat_param)|+)*) => {};
}
patterns!{
    0 | 1 | 2 | 3
}
fn main() {
}

pat

pat 分类符用于匹配任何形式的模式 (pattern),包括 2021 edition 开始的 or-patterns

macro_rules! patterns {
    ($($pat:pat)*) => ();
}

patterns! {
    "literal"
    _
    0..5
    ref mut PatternsAreNice
    0 | 1 | 2 | 3
}
fn main() {}

expr

expr匹配任何形式的表达式.

macro_rules! experssions {
    ($($expr: expr)*) => {};
}
experssions! {
    "abc"
    func()
    func.await
    break 'foo
}
fn main() {}

ty

ty匹配任何形式的类型表达式, 类型表达式是在Rust中表示类型的语法.

macro_rules! types {
    ($($type: ty)*) => {};
}
types! {
    foo::bar
    bool
    [u8]
    impl IntoIterator<Item = u32>
}
fn main() {}

ident

ident匹配任何形式的标识符或者关键字.

macro_rules! idents {
    ($($ident: ident)*) => {};
}
idents! {
    //
    foo
    async
    o_____o
    ___o___
}
fn main() {}

path

path匹配类型中的路径.

macro_rules! paths {
    ($($path: path)*) => {};
}
paths! {
    APath
    ::A::B::C::D
    E::<fff>::G
    FnMut(u32) -> ()
}
fn main() {}

tt

tt 分类符用于匹配标记树 (TokenTree)。tt 分类符是最有作用的分类符之一,因为它能匹配几乎所有东西, 而且能够让你在使用宏之后检查 (inspect) 匹配的内容。

meta

meta匹配属性, 准确的说是属性里面的内容. 通常会在#[$meta: meta]#![$meta: meta] 模式匹配中看到这个.

macro_rules! metas {
    ($($meta: meta)*) => {};
}
metas! {
    ASimplePath
    super::man
    path = "home"
    foo(bar)
}
fn main() {}

lifetime

lifetime匹配生命周期注解或者标签. 和ident很像, 但是lifetime会匹配到前缀'.

macro_rules! lifetimes {
    ($($lifetime: lifetime)*) => { $( println!("lifetime: {}", stringify!($lifetime)); )*};
}
fn main() {
    lifetimes! {
        'static
        'a
        '_
    }
}

vis

vis匹配可能为空的内容. 实际上支持例子里的几种方式,因为这里的 visibility 指的是可见性,与私有性相对。而涉及这方面的内容只有与 pub 的关键字。所以,vis 在关心匹配输入的内容是公有还是私有时有用。

macro_rules! visibilities {
    ($($vis: vis,)*) => {};
}
visibilities! (
    pub,
    ,
);
fn main() {}

literal

literal匹配字面表达式

macro_rules! literals {
    ($($literal: literal)*) => {};
}
literals! {
    -1
    "hello world"
    2.3
    b'b'
    'c'
    true
}
fn main() {}