【问题标题】:Why does the following macro expect a semi-colon when called?为什么以下宏在调用时需要分号?
【发布时间】:2021-04-10 19:29:50
【问题描述】:

我正在尝试编写一个宏来在 rayon 的 par_iter 和 std 的 iter 之间切换,具体取决于构建功能(可能超出了我自己,因为我还没有阅读很多关于宏的内容)。在这里,宏似乎比函数好一点,因为函数可能需要一些相对复杂的类型才能使其工作;如果我想在与如何运行迭代器有关的构建功能中添加更多变体,那么将来宏可能会更加灵活。

#[macro_export]
macro_rules! par_iter {
    ($($tokens:tt)*) => {
      #[cfg(feature = "threaded")]
      $($tokens)*.par_iter()
      #[cfg(not(feature = "threaded"))]
      $($tokens)*.iter()
    }
}

我看到以下错误:

error: macro expansion ignores token `b_slice` and any following
   --> src/util.rs:28:8                                                                      
    | 
28  |       $($tokens)*.iter();
    |        ^^^^^^^^^
    |                                                                                        
   ::: src/counting.rs:219:9                                                                 
    |
219 |         par_iter!(b_slice).map(WordCount::from)                                                                                                                                     
    |         ------------------- help: you might be missing a semicolon here: `;`
    |         |                                                                              
    |         caused by the macro expansion here
    |
    = note: the usage of `par_iter!` is likely invalid in expression context

虽然我不知道第一个错误,但我很好奇为什么需要 ; - 如何使其在表达式上下文中有效?

【问题讨论】:

  • 我猜你不是想评论#[cfg(not(feature = "threaded"))]
  • 抱歉,是的,这是实验中的错误。现已修复。

标签: rust rust-macros


【解决方案1】:

这基本上归结为,您不允许在这样的表达式中使用attributes,例如以下内容无效:

b_slice.iter()
    #[cfg(not(feature = "threaded"))]
    .map(|x| x)
    .collect();

要解决此问题,您可以将它们分配给一个临时变量,如下所示:

注意 {{}} 的双精度,这会导致 block,因此最终表达式是块导致的值。

#[macro_export]
macro_rules! par_iter {
    ($($tokens:tt)*) => {{
        #[cfg(feature = "threaded")]
        let it = $($tokens)*.par_iter();
        #[cfg(not(feature = "threaded"))]
        let it = $($tokens)*.iter();
        it
    }};
}

或者,您也可以将其拆分为两个宏,如下所示:

#[cfg(feature = "threaded")]
#[macro_export]
macro_rules! par_iter {
    ($($tokens:tt)*) => {
        $($tokens)*.par_iter()
    }
}

#[cfg(not(feature = "threaded"))]
#[macro_export]
macro_rules! par_iter {
    ($($tokens:tt)*) => {
        $($tokens)*.iter()
    }
}

【讨论】:

  • 我尝试了第一个,但我只有一个 { 而不是双 {{!我想这是有道理的,因为外部 { 必须只存在于宏中。
  • 没错,使用双 {{ 将所有内容包装在一个块中,然后最终的 it 是该块的结果。 (我已经更新了答案以指出这一点,供未来的读者参考。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-15
  • 2017-03-20
  • 2011-08-05
  • 1970-01-01
  • 2021-12-25
相关资源
最近更新 更多