#dbg #once #debugging #hash-values #print

dbg_if

在循环中使用dbg!避免终端问题

1个不稳定版本

0.1.0 2024年5月16日

#4 in #dbg

MIT/Apache

20KB
221

dbg_if

Maintenance CI crates-io api-docs

dbg!在循环中无需终端问题。

摘要

dbg_once!只在其第一次打印值。

use dbg_if::dbg_once;
for i in 0..10 {
    dbg_once!(i); // Outputs: [src/lib.rs:9:9] x = 0
}

dbg_if_ne!只打印更改的值。

use dbg_if::dbg_if_ne;
fn f(x: u8) -> u8 {
    dbg_if_ne!(x, u8)
}
f(1); // Outputs: [src/lib.rs:58:9] x = 1
f(1); // No output.
f(2); // Outputs: [src/lib.rs:58:9] x = 2

dbg_if_hash_ne!仅在更改的哈希值上打印。

use dbg_if::dbg_if_hash_ne;
let mut s: String = "hello".into();
fn f(x: &str) -> &str {
    dbg_if_hash_ne!(x)
}
f(&s); // Outputs: [src/lib.rs:37:9] x = "hello"
f(&s); // No output.
s.push('!');
f(&s); // Outputs: [src/lib.rs:37:9] x = "hello!"

姐妹宏once!was_ne!was_hash_ne!返回true而不是打印。

最后,宏dbg_if提供了一种对dbg的替代方案,如果这是您的首选。

use dbg_if::dbg_if as dbg;
let mut x: u8 = 0;
fn f(x: u8) -> u8 {
    dbg!(x + 1);
    dbg!(x + 2, Once);
    dbg!(x + 3, IfNe, u8);
    dbg!(x + 4, IfHashNe)
}

x = f(x); 
// Outputs:
// [src/lib.rs:10:9] x + 1 = 1
// [src/lib.rs:11:9] x + 2 = 2
// [src/lib.rs:12:9] x + 3 = 3
// [src/lib.rs:13:9] x + 4 = 4
x = f(x); 
// Outputs:
// [src/lib.rs:10:9] x + 1 = 1

功能 "float"

如果启用功能 "float",则这些宏可用

这些可以作为was_ne!dbg_if_ne!的第三个参数提供。有关更多信息,请参阅approx存储库。

#[cfg(feature = "float")]
{
use dbg_if::{dbg_if_ne, abs_diff_ne_args};
fn f(x: f32) -> f32 {
    dbg_if_ne!(x, f32, abs_diff_ne_args!(epsilon = 1.0))
}
f(1.0); // Outputs: [src/lib.rs:42:9] x = 1.0
f(1.5); // No output.
f(2.0); // No output.
f(2.1); // Outputs: [src/lib.rs:42:9] x = 2.1
}

目标

  • 在不使用调试器的情况下简化调试检查。

动机

fn f(x: u8) -> u8 {
  dbg!(x) + 1
}
assert_eq!(f(1), 2);

dbg!宏很棒。它就像能够直接将探头添加到您的代码中,而不会打扰到一切,因为它在表达式上工作并允许它们“通过”。对于直接代码,它是完美的。

但在循环中不行

fn f(x: u8) -> u8 {
    let mut accum = 0;
    for i in 0..100 {
        accum += dbg!(x);
    }
    accum
}
[src/main.rs:59:18] x = 1 
[src/main.rs:59:18] x = 1 
[src/main.rs:59:18] x = 1 
...^C

然而,对于密集循环中的代码,dbg!还有一些不足之处。终端会反复尖叫“x = 1”。一定有更好的方法。

我们能做得更好吗?

是的!让我们记录调用点的值——使用静态原子变量——而不是将相同的信息不断发送到终端,我们可以在值发生变化时,使用dbg_if_ne!来输出信息。

use dbg_if::dbg_if_ne;
fn f(x: u8) -> u8 {
    let mut accum = 0;
    for i in 0..5 {
        accum += dbg_if_ne!(x, u8);
    }
    accum
}
f(1); // Outputs: [src/main.rs:59:18] x = 1 

但是我有非原子值?

这没有关系。它们可以被哈希吗?因为哈希可以在调用点的AtomicU64中存储。只需使用dbg_if_hash_ne!

测试

一些测试需要特定的设置才能成功运行。在.cargo/config.toml中放置了一些别名,以便运行这些测试。

  • cargo test运行was*测试。
  • cargo test-output运行上述测试以及dbg*测试,这些测试验证其输出在stdout上。
  • cargo test-all运行上述测试以及浮点特性。

如果您看到错误信息“重定向已存在”,那是因为一些测试检查了stdout,并且不能多线程运行。请使用cargo test-output并使用正确的参数来运行它们。

许可协议

您可以选择在以下任一协议下使用此软件包:

贡献

除非您明确说明,否则根据Apache-2.0许可证定义的您提交的任何旨在包含在作品中的贡献,都将按照上述协议双重许可,不附加任何额外条款或条件。

致谢

感谢Philipp Oppermann及其软件包once。最初我以为我只会编写dbg_once!并提交一个PR。但是当我开始编写时,我发现dbg_if_ne!也有用,这些都需要stdonce是一个no_std软件包。因此,dbg_if受到了once的启发和指导,但实际上它与once没有共享任何代码。

依赖项

~49KB