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

Posted

技术标签:

【中文标题】Rust 声明性宏中的 @ 符号是啥意思?【英文标题】:What does an @ symbol mean in a Rust declarative macro?Rust 声明性宏中的 @ 符号是什么意思? 【发布时间】:2019-06-21 17:09:47 【问题描述】:

我已经看到宏中使用了@ 符号,但我在 Rust Book 或任何官方文档或博客文章中都找不到它的提及。例如,在this Stack Overflow answer 中是这样使用的:

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());

从用法看来,它似乎是用于声明另一个宏,它是主宏的本地宏。

这个符号是什么意思,为什么要使用它而不是创建另一个***宏?

【问题讨论】:

【参考方案1】:

在宏的模式匹配部分,符号可以表示作者希望它们表示的任何含义。前导符号@ 通常用于表示宏的“实现细节”——外部用户不希望使用的宏的一部分。

在此示例中,我使用它对元组参数进行模式匹配以获取元组参数的计数。

在宏之外,@ 符号用于匹配模式,同时也为整个模式指定名称:

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

稍微延伸一下,同样的逻辑可以应用于宏中的使用——我们正在对元组进行模式匹配,但也为该特定模式附加了一个名称。我认为我什至看到人们使用更平行的东西:(count @ ...。但是,The Little Book of Rust Macros 指出:

使用@ 的原因是,从Rust 1.2 开始,@ 标记不用于前缀位置;因此,它不能与任何东西发生冲突。可以根据需要使用其他符号或唯一前缀,但 @ 的使用已经开始变得普遍,因此使用它可以帮助读者理解您的代码。


而不仅仅是创建另一个***宏

创建另一个宏可能是更好的做法,但仅限于现代 Rust。在最近对 Rust 进行的更改使您可以直接导入宏之前,对于尝试有选择地导入宏的最终用户来说,拥有多个宏可能会很棘手。

另见:

Internal rules in The Little Book of Rust Macros Why must I use macros only used by my dependencies What does the '@' symbol do in Rust? Appendix B: Operators and Symbols

【讨论】:

啊……太明显了!我不知何故认为这是一种特殊的语法,无法动摇这个想法。 等等x @ 0 就等于x if x == 0?引入另一个符号有什么意义? @OptimisticPeach 当然,这不是一个常见的用例,但在某些情况下,您需要进行模式匹配和绑定名称。 A quickly-created example。您也可以为匹配守卫提出相同的论点,因为很多时候它们可以是匹配臂中的if 表达式。 $($ename::$vname(..) => instructions!(@count ($($vty),*))),* - 我没有得到这部分。 $vname(..)里面的参数个数怎么和右边$vty的个数相等。

以上是关于Rust 声明性宏中的 @ 符号是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章

在声明性宏中构建所有元素对(二次集)

Rust 宏中的 tt 元变量类型是啥意思?

Haskell 类型声明中的符号 `!` 是啥意思?

C++11 中的 T&&(双 & 符号)是啥意思?

这个符号 `:>` 在 Coq 中是啥意思?

vb中符号常量的作用范围是啥?