Rust有调试宏吗?

27

在C++中,我使用类似这样的DEBUG宏:

#ifdef DEBUG
#define DEBUG_STDERR(x) (std::cerr << (x))
#define DEBUG_STDOUT(x) (std::cout << (x))
#else 
#define DEBUG_STDERR(x)
#define DEBUG_STDOUT(x)
#endif

Rust有类似的东西吗?

4个回答

38

Rust 1.32.0

Rust 1.32.0稳定了dbg!()宏,该宏输出:

  • 调用该宏的文件名。
  • 调用该宏的行号。
  • 参数的漂亮打印(必须实现Debug trait)。

注意:dbg!()移动其参数,因此您可能希望通过引用传递非复制类型。

示例:点数组(Playground

#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let points = [
        Point { x: 0, y: 0 },
        Point { x: 2, y: 3 },
        Point { x: 5, y: 7 },
    ];

    dbg!(&points);
}

程序输出

[src/main.rs:14] &points = [
    Point {
        x: 0,
        y: 0
    },
    Point {
        x: 2,
        y: 3
    },
    Point {
        x: 5,
        y: 7
    }
]

示例:条件编译(Playground

原帖提到只想在调试模式下显示调试内容。

以下是实现此功能的一种方法:

#[cfg(debug_assertions)]
macro_rules! debug {
    ($x:expr) => { dbg!($x) }
}

#[cfg(not(debug_assertions))]
macro_rules! debug {
    ($x:expr) => { std::convert::identity($x) }
}

fn main() {
    let x = 4;
    debug!(x);
    if debug!(x == 5) {
        println!("x == 5");
    } else {
        println!("x != 5");
    }
}

程序输出(调试模式)

---------------------Standard Error-----------------------

[src/main.rs:13] x = 4
[src/main.rs:14] x == 5 = false

---------------------Standard Output----------------------

x != 5

程序输出(发布模式)

---------------------Standard Output----------------------

x != 5

在 Rust 1.32.0 之前

你可以使用 log crate,或者自己定义一个


1
我已经安装了 Rust 1.50,但即使使用“cargo build --release”编译,我仍然得到输出?如何在发布模式下禁用它? - MappaM
1
@MappaM 这是预期的,因为 dbg! 旨在用于调试和发布版本。官方文档明确说明了其目的:请注意,该宏旨在作为调试工具使用,因此您应避免长时间在版本控制中使用它。对于需要添加到版本控制的调试输出的用例,最好使用 log 包中的 debug! 等宏来实现。 - legends2k
如所示,dbg!还会返回其参数(这就是为什么它必须将其移动)因此它可以用于包装任何表达式(只要它的类型是Debug)。 - BallpointBen

15

虽然像DK的答案提到的使用log组件是有意义的,但以下是如何直接实现你所要求的等效方法:

// The debug version
#[cfg(feature = "my_debug")]
macro_rules! debug_print {
    ($( $args:expr ),*) => { println!( $( $args ),* ); }
}

// Non-debug version
#[cfg(not(feature = "my_debug"))]
macro_rules! debug_print {
    ($( $args:expr ),*) => {}
}

fn main() {
    debug_print!("Debug only {}", 123);
}

在您的 Cargo.toml 文件中,添加一个 [features] 部分:

[features]
my_debug = []

使用cargo run --features my_debug命令运行程序可以看到输出,而使用普通的cargo run则看不到。


9
可以通过借鉴现有的 debug_assertions 属性来使得这段代码更加简洁,该属性可以控制像 debug_assert! 这样的宏。只需将 #[cfg(feature = "my_debug")] 更改为 #[cfg(debug_assertions)] 并删除对 Cargo.toml 的更改。这样,在发布版本中,调试代码就会自动被忽略! - CJ McAllister
现在会出现“错误:扩展为项的宏必须用大括号括起来或跟着分号”。 - MappaM

8
你可以自己定义它们,但使用log crate会更简单,该crate为各种目的定义了几个宏(请参见 log文档)。
请注意,该crate仅提供日志记录的前端;您还需要选择一个后端。 log文档中有一个基本示例,或者您可以使用类似于env_loggerlog4rs之类的工具。

3

基于Chris Emerson的回答和CJ McAllister的评论的宏

// Disable warnings

#[allow(unused_macros)]

// The debug version

#[cfg(debug_assertions)]
macro_rules! log {
    ($( $args:expr ),*) => { println!( $( $args ),* ); }
}

// Non-debug version

#[cfg(not(debug_assertions))]
macro_rules! log {
    ($( $args:expr ),*) => {()}
}

使用

log!("Don't be crazy");
log!("Answer is {}", 42);

使用cargo build --release进行构建将会将所有的log!(...)替换为单元元组();

我没有找到替换为空的方法,但我认为编译器会自动处理。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接