【问题标题】:Is it possible to use an item arg passed to a macro as a method?是否可以使用传递给宏的项目参数作为方法?
【发布时间】:2017-05-29 22:01:09
【问题描述】:

我正在尝试创建一个宏,该宏生成一个struct,它提供了一组传递给宏的方法。例如,调用:

create_impl!(StructName, fn foo() -> u32 { return 432 })

应该生成一个空结构StructName,它提供方法foo()

我最初尝试使用 item 宏 arg 类型。但是,当我尝试在规则中使用 item 时,出现以下编译器错误:

error: expected one of `const`, `default`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `fn foo() -> u32 { return 42; }`
  --> src/lib.rs:40:13
   |
40 |           $($function)*
   |             ^^^^^^^^^

是否可以使用item 参数以这种方式在生成的结构中定义方法?我有什么遗漏吗?

这是我定义的完整宏:

macro_rules! create_impl {

  ($struct_name:ident, $($function:item),*) => {
      struct $struct_name {
      }

      impl $struct_name {
          // This is the part that fails.
          $($function)*
      }
  };

}

【问题讨论】:

  • 我认为 methods 根本不是项目。当我将 fn foo() 更改为 fn foo(self) 时,我得到 error: expected one of :: or :, found ) (如果您在宏之外编写,则会发生同样的错误) .

标签: rust rust-macros


【解决方案1】:

简短的回答是“不,您不能将 item 匹配器用于方法”。

根据reference,项目是板条箱或模块中的顶级事物,因此函数、类型等等。虽然 structimpl 块是一个项目,但它们里面的东西不是。尽管在语法上,方法定义看起来与顶级函数相同,但这并不能使其成为项目。

Rust 宏系统的工作方式是,一旦片段被解析为 item,例如使用$foo:item,它永远是item;一旦宏展开,它就会被拆分回标记以便重新解析。

这样的结果是$foo:item只能在宏的输出中的item位置,一般表示顶级。

有几种选择。

最简单的是使用旧的tt(令牌树)匹配器。令牌树要么是非括号令牌,要么是由平衡括号包围的令牌序列;所以$(foo:tt)* 匹配任何东西。但是,这意味着它也会吞噬逗号,因此在每个项目周围添加大括号会更容易:

macro_rules! create_impl {

  ($struct_name:ident, $({ $($function:tt)* }),*) => {
      struct $struct_name {
      }

      impl $struct_name {
          $($($function)*)*
      }
  };

}

然后你必须使用额外的大括号:

create_impl!(StructName, { fn foo() -> u32 { return 432 } }, { fn bar() -> u32 { return 765 } });

你也可以直接匹配你想要的语法,而不是委托给item匹配器:

macro_rules! create_impl2 {
    ($struct_name:ident, $(fn $fname:ident($($arg:tt)*) -> $t:ty $body:block),*) => {
      struct $struct_name {
      }

      impl $struct_name {
          $(fn $fname($($arg)*) -> $t $body)*
      }
    }
}

当然,因为它是显式的,这意味着如果你想支持没有返回类型的函数,你需要在你的宏中添加另一个 case。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-30
    • 1970-01-01
    • 2010-10-05
    • 2023-03-09
    相关资源
    最近更新 更多