了解dbg!Rust 中的宏

ANi*_*120 0 rust

我正在尝试编写一些自己的调试宏,并正在查看 rusts 构建的源代码dbg!

macro_rules! dbg {
    () => {
        $crate::eprintln!("[{}:{}]", $crate::file!(), $crate::line!());
    };
    ($val:expr $(,)?) => {
        // Use of `match` here is intentional because it affects the lifetimes
        // of temporaries - https://stackoverflow.com/a/48732525/1063961
        match $val {
            tmp => {
                $crate::eprintln!("[{}:{}] {} = {:#?}",
                    $crate::file!(), $crate::line!(), $crate::stringify!($val), &tmp);
                tmp
            }
        }
    };
    ($($val:expr),+ $(,)?) => {
        ($($crate::dbg!($val)),+,)
    };
}
Run Code Online (Sandbox Code Playgroud)

关于这段代码,有几点让我感到困惑:

  1. $贯穿这段代码的操作符在做什么?
  2. 平面语言相当于什么($val:expr $(,)?)?我不明白它,是什么以及为什么它在那里。
  3. 为什么宏定义以 开头() => {$crate::eprintln!("[{}:{}]", $crate::file!(), $crate::line!());};

kmd*_*eko 5

贯穿这段代码的 $ 运算符在做什么?

macro_rules!在普通 Rust 之上有独特的语法。s$用于指示元变量(如$ident)和重复项(如$(...))。您可能应该对 Rust 宏是什么进行一些初步研究:


平面语言相当于什么($val:expr $(,)?)?我不明白它,是什么以及为什么它在那里。

定义$val:expr将匹配单个表达式的模式。匹配$(,)?a,可能存在零次或一次。有效地使得 willdbg!允许可选的尾随逗号(以便模仿大多数 Rust)。您将看到这一点反映在其他模式中$($val:expr),+ $(,)?


为什么宏定义以 开头() => {$crate::eprintln!("[{}:{}]", $crate::file!(), $crate::line!());};

该宏被设计为使用任意数量的参数(包括零)来调用。该() => { ... };模式允许dbg!()有效。不带参数调用的效果dbg!是仅记录文件和行号。