我编写了一个小宏来帮助我探索事物被解析为什么.砍掉几只胳膊后,看起来就像:

macro_rules! show_me{
    ($l : literal $($tail : tt)*) => {
        println!("{} is a literal and then I see {}", stringify!($l), stringify!($($tail)*));
        show_me!($($tail)*)
    };
    (- $($tail : tt)*) => {
        println!("{} is a - and then I see {}", stringify!(-), stringify!($($tail)*));
        show_me!($($tail)*)
    };
    ($i : ident $($tail : tt)*) => {
        println!("{} is an ident and then I see {}", stringify!($i), stringify!($($tail)*));
        show_me!($($tail)*)
    };
    ($token : tt $($tail : tt)*) => {
        println!("{} is a mystery and then I see {}", stringify!($token), stringify!($($tail)*));
        show_me!($($tail)*)
    };
    () => {}
}

这在使用Rustc 1.66.0(69f9c33d7 2022-12-12)的某些输入上表现出预期的行为:

show_me!(x + 1);
# x is an ident and then I see + 1
# + is a mystery and then I see 1
# 1 is a literal and then I see

但如果我try 一个负数,我会(有点)惊讶:

show_me!(-4);
# -4 is a literal and then I see 

这将是完全有意义的,除了https://doc.rust-lang.org/reference/procedural-macros.html说(在声明性宏的描述下):

  • 字面值("字符串",1等)

    注意,否定(例如-1)从来不是这种字面标记的一部分, 而是一个单独的操作员令牌.

让我感到奇怪的是,如果我试着跑show_me!(-x)米:

error: unexpected token: `x`
  --> src/main.rs:54:15
   |
54 |     show_me!(-x);
   |               ^
   |
  ::: src/utils/macros.rs:27:6
   |
27 |     ($l : literal $($tail : tt)*) => {
   |      ------------ while parsing argument for this `literal` macro fragment

请注意,如果我注释掉show_meliteral个手臂,或者只是将其移动到匹配器的底部,其他手臂对此非常满意:

show_me!(-x);
# - is a - and then I see x
# x is an ident and then I see 

我的预期是,匹配的手臂要么匹配成功,要么进入下一种模式.相反,它引发了编译错误.在这种情况下发生了什么?

另外,我是误读了文档还是它是不正确的?对我来说,它似乎清楚地表明,-永远不应该是声明性宏中文字表达式的一部分(尽管它可能是过程性宏中的一部分).

推荐答案

issue #82968人问了这个问题,得到的回答是:

这是预期的工作,非终端元变量总是完全致力于解析语法的一部分,如果失败,整个宏调用将被拒绝.

你可以看到同样的行为,比如expr.

Rust相关问答推荐

重新导出proc宏导致未解决的extern crate错误""

程序退出后只写入指定管道的数据

将JSON密钥转换为Polars DataFrame

将大小为零的类型实例存储到空指针中

有没有更好的方法从HashMap的条目初始化 struct ?

如何使用 list 在Rust for Windows中编译?

如何正确地将App handler传递给Tauri中的其他模块?

使用铁 rust S还原对多个数组执行顺序kronecker积

铁 rust 中的泛型:不能将`<;T作为添加>;::Output`除以`{Float}`

从未排序的链表中删除重复项的铁 rust 代码在ELSE分支的低级上做了什么?

Rust 中什么时候可以返回函数生成的字符串切片&str?

是否可以在不直接重复的情况下为许多特定类型实现一个函数?

如何在 `connect_activate()` 之外创建一个 `glib::MainContext::channel()` 并将其传入?

提取指向特征函数的原始指针

Rust FFI 和 CUDA C 性能差异

如何在 Rust Polars 中可靠地连接 LazyFrames

有没有办法在 Rust 中对 BigInt 进行正确的位移?

如何构建包含本地依赖项的 docker 镜像?

如何在 Rust 中构建一个 str

返回 &str 但不是 String 时,borrow 时间比预期长