Rust 声明性宏中的 @ 符号是什么意思? [英] What does an @ symbol mean in a Rust declarative macro?

查看:70
本文介绍了Rust 声明性宏中的 @ 符号是什么意思?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

macro_rules!指示 {(枚举 $ename:ident {$($vname:ident ( $($vty: ty),* )),*}) =>{枚举 $ename {$($vname ( $($vty),* )),*}impl $ename {fn len(&self) ->使用{匹配自我{$($ename::$vname(..) => 说明!(@count ($($vty),*))),*}}}};(@count()) =>(0);(@count ($a:ty)) =>(1);(@count ($a:ty, $b:ty)) =>(2);(@count ($a:ty, $b:ty, $c:ty)) =>(3);}指示!{枚举指令{没有任何(),一(u8),两个(u8, u8),三(u8, u8, u8)}}fn 主(){println!("{}", Instruction::None().len());println!("{}", Instruction::One(1).len());println!("{}", Instruction::Two(1, 2).len());println!("{}", Instruction::Three(1, 2, 3).len());}

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

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

解决方案

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

在这个例子中,我用它来模式匹配元组参数以获得元组参数的计数.

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

匹配年龄{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 的更改使您可以直接导入宏之前,对于尝试有选择地导入宏的最终用户来说,拥有多个宏可能会很棘手.

另见:

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. For example, in this Stack Overflow answer it is used like this:

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:

The reason for using @ is that, as of Rust 1.2, the @ token is not used in prefix position; 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. 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.

See also:

这篇关于Rust 声明性宏中的 @ 符号是什么意思?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆