简体   繁体   English

Rust 声明性宏中的 @ 符号是什么意思?

[英]What does an @ symbol mean in a Rust declarative macro?

I have seen the @ symbol used in macros but I cannot find mention of it in the Rust Book or in any official documentation or blog posts.我见过宏中使用的@符号,但在 Rust Book 或任何官方文档或博客文章中找不到提及它。 For example, in this Stack Overflow answer it is used like this:例如,在这个 Stack Overflow 答案中,它是这样使用的:

macro_rules! instructions {
    (enum $ename:ident {
        $($vname:ident ( $($vty: ty),* )),*
    }) => {
        enum $ename {
            $($vname ( $($vty),* )),*
        }

        impl $ename {
            fn len(&self) -> usize {
                match self {
                    $($ename::$vname(..) => instructions!(@count ($($vty),*))),*
                }
            }
        }
    };

    (@count ()) => (0);
    (@count ($a:ty)) => (1);
    (@count ($a:ty, $b:ty)) => (2);
    (@count ($a:ty, $b:ty, $c:ty)) => (3);
}

instructions! {
    enum Instruction {
        None(),
        One(u8),
        Two(u8, u8),
        Three(u8, u8, u8)
    }
}

fn main() {
    println!("{}", Instruction::None().len());
    println!("{}", Instruction::One(1).len());
    println!("{}", Instruction::Two(1, 2).len());
    println!("{}", Instruction::Three(1, 2, 3).len());
}

From the usage, it appears that it is used for declaring another macro that is local to the main one.从用法来看,它似乎用于声明另一个主宏的本地宏。

What does this symbol mean and why would you use it rather than just creating another top-level macro?这个符号是什么意思,为什么要使用它而不是仅仅创建另一个顶级宏?

In the pattern-matching part of a macro, symbols can mean whatever the author desires them to mean.在宏的模式匹配部分,符号可以表示作者希望它们表示的任何内容。 A leading symbol @ is often used to denote an "implementation detail" of the macro — a part of the macro that an external user is not expected to use.前导符号@通常用于表示宏的“实现细节”——外部用户不希望使用的宏的一部分。

In this example, I used it to pattern-match the tuple parameters to get a count of the tuple parameters.在这个例子中,我用它来模式匹配元组参数以获取元组参数的计数。

Outside of macros, the @ symbol is used to match a pattern while also assigning a name to the entire pattern:在宏之外, @符号用于匹配模式,同时还为整个模式分配一个名称:

match age {
    x @ 0 => println!("0: {}", x),
    y @ 1 => println!("1: {}", y),
    z => println!("{}", z),
}

With a bit of a stretch, this same logic can be applied to the use in the macro — we are pattern-matching the tuple, but also attaching a name to that specific pattern.稍微延伸一下,同样的逻辑可以应用于宏中的使用——我们对元组进行模式匹配,但也为该特定模式附加了一个名称。 I think I've even seen people use something even more parallel: (count @ ... . However,The Little Book of Rust Macros points out:我什至看到人们使用更平行的东西:( (count @ ... 。然而,The Little Book of Rust Macros指出:

The reason for using @ is that, as of Rust 1.2, the @ token is not used in prefix position;使用@的原因是,从 Rust 1.2 开始, @标记不再用于前缀位置; as such, it cannot conflict with anything.因此,它不能与任何东西冲突。 Other symbols or unique prefixes may be used as desired, but use of @ has started to become widespread, so using it may aid readers in understanding your code.可以根据需要使用其他符号或唯一前缀,但@使用已经开始变得普遍,因此使用它可以帮助读者理解您的代码。


rather than just creating another top-level macro而不是仅仅创建另一个顶级宏

Creating another macro is likely better practice, but only in modern Rust.创建另一个宏可能是更好的做法,但仅限于现代 Rust。 Before recent changes to Rust that made it so you could import macros directly, having multiple macros could be tricky for end users who tried to selectively import macros.在最近对 Rust 的更改使您可以直接导入宏之前,对于尝试有选择地导入宏的最终用户来说,拥有多个宏可能会很棘手。

See also:也可以看看:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM