Rust 声明式宏中的 Metavariables 有哪些
阅读原文时间:2023年08月09日阅读:1

Metavariables

官方文档确实写得很好,但是缺少一些风味,容易催眠‍

还是直接看例子更爽一些,通常我们可以从示例代码中之间看出官方文档要表达的意思,而且很多时候我们可以直接在示例代码的基础上改一改,就能满足我们自己的定制化需求。越抽象的东西,越是如此


An item is a component of a crate. Items are organized within a crate by a nested set of modules. Every crate has a single "outermost" anonymous module; all further items within the crate have paths within the module tree of the crate.

There are several kinds of items:

  • modules
  • extern crate declarations
  • use declarations
  • function definitions
  • type definitions
  • struct definitions
  • enumeration definitions
  • union definitions
  • constant items
  • static items
  • trait definitions
  • implementations
  • extern blocks

可以把整个 crate 比作一个 struct,这个 struct 里面的每一个 field 都是一个 item

这些 item 包括每一个 struct, fn, mod 的定义…

macro_rules! test_item {
    ($x: item) => {
        // #[derive(Debug)]
        $x
    }
}

test_item!(#[derive(Debug)] struct A{a: i32});
test_item!(fn foo(){println!("foo");});
test_item!(mod ma{});

let a = A{ a: 9};
println!("a: {:?}", a); // 输出 a: A { a: 9 }

foo(); // 输出 foo

block 是匿名的命名空间作用域(anonymous namespace scope),就是以 { 开始 以 } 结束的整个块

macro_rules! test_block {
    ($x: block) => {
        $x
    }
}

test_block!({
    println!("block");
});

A statement is a component of a block, which is in turn a component of an outer expression or function

一个 stmt 可以是一个前面的 [item](## item), 或是 let statement, 或是 expression statement, 或是宏调用

macro_rules! test_stmt {
    ($x: stmt) => {
        $x
    }
}

// let statement
test_stmt!(let state = 8);
println!("state: {}", state);

// item
test_stmt!(#[derive(Debug)] struct B{b: i32});

// expression statement
test_stmt!{
    if true {
        1
    } else {
        2
    }
};

// Macro Invocation
test_stmt!{
    println!("Macro Invocation")
};

用来 pattern match 的 param, 匹配一个 pattern, 像 match 内 => 左边的那些东西

pat_param 默认不匹配 or-pattern: 0 | 1 | 2

macro_rules! test_pat_param {
    ($x: pat_param) => {
        $x
    }
}

struct Person {
    car: Option<String>,
    age: u8,
    name: String,
    gender: u8,
    gfs: [String; 3],
}

let person = Person {
    car: Some("bmw".into()),
    age: 18,
    name: "hansomeboy".into(),
    gender: 1,
    gfs: ["Lisa".into(), "Jennie".into(), "Rosé".into()],
};

if let test_pat_param!(
    Person {
            car: Some(_),
            age: person_age @ 13..=19,
            name: ref person_name,
            gfs: ref whole @ [.., ref last],
            ..
        }
) = person {
    println!("{} has a car and is {} years old, and his last GF is {}.", person_name, person_age, last);
}

macro_rules! test_or_pattern {
    ($($x: pat_param)*) => ();
}

test_or_pattern!{
    Some(_)
    Foo{x}
    // error: no rules expected the token `|`
    // 0 | 1 | 2
}

输出: hansomeboy has a car and is 18 years old, and his last GF is Rosé.

用来匹配任意类型的 pattern, 包括 or-pattern: 0 | 1 | 2

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

test_pat! {
    "literal"
    _
    0..5
    ref mut PatternsAreNice
    0 | 1 | 2 | 3
}

一个表达式 Expression

macro_rules! test_expr {
    ($($x: expr)*) => ();
}

test_expr!{
    "hello" // LiteralExpression
    42 // LiteralExpression
    a::b::c // PathExpression
    a * b + c // OperatorExpression
    &a
    *a
    -a
    a = b
    a += b
    a || b && c
    a & b | c
    (a+b) - c
    ["a"] // ArrayExpression
    a[b][c] // IndexExpression
    ("world", 42) // TupleExpression
    tuple.0 // TupleIndexingExpression
    Point {x: 1.0, y: 2.0} // StructExpression
    foo() // CallExpression
    "3.14".parse() // MethodCallExpression
    foo().await // AwaitExpression
    bar.await
    hello.world // FieldExpression
    move|x,y| -> () {} // ClosureExpression
    async move {} // AsyncBlockExpression
    0..10 // RangeExpression
    (_, a) // UnderscoreExpression
    vec![1,2,3] // MacroInvocation
    continue 'hello // ContinueExpression
    break 'hello // BreakExpression
    return 42 // ReturnExpression
    {} // BlockExpression
    #[cfg("hello")]{}
    unsafe {} // UnsafeExpression
    if condition {} // IfExpression
    if let a=b {} // IfLetExpression
    match x {} // MatchExpression
}

一个类型 Type

macro_rules! test_ty {
    ($($x: ty)*) => ();
}

test_ty! {
    u32
    bool
    char
    str
    String
    [u8; 128]
    (u32, bool)
    &[u8]
    Hello // User-defined types
    fn(u8, u8) -> ()
    &mut reference
    *mut pointer
    *const pointer
    dyn Trait // Trait Object
    impl Trait // Impl Trait
}

一个标识符(用来标识变量、函数、类、对象或其他程序实体的名称) an IDENTIFIER_OR_KEYWORD or RAW_IDENTIFIER

macro_rules! test_ident {
    ($($x: ident)*) => ();
}

test_ident! {
    foo
    _identifier
    r#true // raw identifier
    深圳
}


macro_rules! test_path {
    ($($x: path)*) => ();
}

test_path! {
    a::b::c
    self::a::<b>::c
    ::std::time::Instant::now()
}

标记树(token tree) 是一种介于标记 (token) 与 AST(abstract syntax tree) 之间的东西

几乎所有的 token 都是 token tree 的叶子节点(leaf node), 只有被 (...), [...]{...} 包裹在一起的一组一组的 tokens 不是叶子节点

a + b + (c + d[0]) + e

会被解析成下面的 token tree:

«a» «+» «b» «+» «(   )» «+» «e»
          ╭────────┴──────────╮
           «c» «+» «d» «[   ]»
                        ╭─┴─╮
                         «0»

可以看出 token tree 的 root 节点其实是第一行的这一整组 token: «a» «+» «b» «+» «( )» «+» «e», 而不是单一的 node

而 AST 会生成下面这种只有一个 root 节点的数状结构:

              ┌─────────┐
              │ BinOp   │
              │ op: Add │
            ┌╴│ lhs: ◌  │
┌─────────┐ │ │ rhs: ◌  │╶┐ ┌─────────┐
│ Var     │╶┘ └─────────┘ └╴│ BinOp   │
│ name: a │                 │ op: Add │
└─────────┘               ┌╴│ lhs: ◌  │
              ┌─────────┐ │ │ rhs: ◌  │╶┐ ┌─────────┐
              │ Var     │╶┘ └─────────┘ └╴│ BinOp   │
              │ name: b │                 │ op: Add │
              └─────────┘               ┌╴│ lhs: ◌  │
                            ┌─────────┐ │ │ rhs: ◌  │╶┐ ┌─────────┐
                            │ BinOp   │╶┘ └─────────┘ └╴│ Var     │
                            │ op: Add │                 │ name: e │
                          ┌╴│ lhs: ◌  │                 └─────────┘
              ┌─────────┐ │ │ rhs: ◌  │╶┐ ┌─────────┐
              │ Var     │╶┘ └─────────┘ └╴│ Index   │
              │ name: c │               ┌╴│ arr: ◌  │
              └─────────┘   ┌─────────┐ │ │ ind: ◌  │╶┐ ┌─────────┐
                            │ Var     │╶┘ └─────────┘ └╴│ LitInt  │
                            │ name: d │                 │ val: 0  │
                            └─────────┘                 └─────────┘


macro_rules! test_tt {
    ($($x: tt)*) => {
        println!("test_tt:");
        $( println!("{:?}", stringify!($x)); )*
    }
}

test_tt! {
    (a + b + (c + d[0]) + e)
    [a + b + (c + d[0]) + e]
    {a + b + (c + d[0]) + e}
}
test_tt! {
    a + b + (c + d[2]) + e
}

输出:

test_tt:
"(a + b + (c + d [0]) + e)"
"[a + b + (c + d [0]) + e]"
"{ a + b + (c + d [0]) + e }"
test_tt:
"a"
"+"
"b"
"+"
"(c + d [2])"
"+"
"e"

用来匹配 attribute 属性

就是那些写在 struct/enum/fn 前面的 #[...] #![...]

macro_rules! test_meta {
    ($(#$(!)?[$meta: meta])*) => ();
}

test_meta! {
    #[hello]
    #![world]
    #[a="b"]
}


macro_rules! test_lifetime {
    ($($x: lifetime)*) => ();
}

test_lifetime! {
    'a
    '_
    'static
}

visibility-and-privacy

macro_rules! test_vis {
    //        ∨~~Note this comma, since we cannot repeat a `vis` fragment on its own
    ($($x: vis,)*) => ();
}

test_vis! {
    ,
    pub,
    pub(crate),
    pub(super),
    pub(self),
    pub(in crate::a::b),
}


macro_rules! test_literal {
    ($($x: literal)*) => ();
}

test_literal! {
    0
    b'x'
    'x'
    "hello"
    true
}

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章