【问题标题】:error: variable 'x' is still repeating at this depth错误:变量“x”仍在此深度重复
【发布时间】:2024-04-14 17:10:02
【问题描述】:

我正在尝试编写一个宏来计算各种函数的执行时间。

macro_rules! timer {
    ($( $x: expr ),+ ) => {
        let now = SystemTime::now();
        let val = $x;

        match now.elapsed() {
            Ok(elapsed) => {
                // This should include a message at some point alongside the timing
                println!("{}", elapsed.as_secs());
            }
            Err(e) => {
                println!("{:?}", e);
            }
        }
        val
    } 
}

但是编译器会抛出一个error: variable 'x' is still repeating at this depth

在我在 (F#) 中尝试过的另一种静态类型语言中,使用闭包是最简单的方法。在 Rust 中不可能有这样的通用宏吗?

【问题讨论】:

  • 问题是宏接受一个或多个表达式,但它只使用一个。它应该做什么?块是否应该为每个输入表达式扩展一次并只返回最后一个?还是应该返回所有这些?一起计时还是单独计时?并且只是补充一点:您可以使用常规函数轻松完成此操作;你不是有什么原因吗?
  • @DK。我对宏语法的理解是它必须是零或一对多的重复(尽管我更喜欢匹配和评估一个表达式)。至于为什么我不使用常规函数来计时,我只是想感受一下语言中的宏。这可能(?)不合适。

标签: macros rust


【解决方案1】:

最直接的问题是您要求宏解析一个或多个表达式的序列,而扩展只能处理一个。所以只需要求一个。

其次,您希望扩展生成一个表达式,但您已经将其编写为扩展为多个语句。要解决此问题,请展开为一个块。

解决这些问题:

macro_rules! timer {
    ($x: expr) => {
        {
            let now = SystemTime::now();
            let val = $x;

            match now.elapsed() {
                Ok(elapsed) => {
                    // This should include a message at some point alongside the timing
                    println!("{}", elapsed.as_secs());
                }
                Err(e) => {
                    println!("{:?}", e);
                }
            }
            val
        }
    } 
}

【讨论】: