#input #println #cleaner #macro #print-clean

printc

Print-clean 宏。类似于 println!,但输入更简洁。

1 个不稳定版本

0.1.2 2022年10月22日
0.1.1 2022年10月22日
0.1.0 2022年10月22日

#1410 in Rust 模式

MIT 许可证

17KB

用法

将以下内容添加到您的 Cargo.toml

[dependencies]
printc = "0.1"

示例

#[macro_use] extern crate printc;

fn main() {
    let x = 500;
    printc!(x);
}

输出

x = 500

问题陈述

为什么要在杂乱的输入(println!)和杂乱的输出(dbg!)之间选择?printc! 允许您同时使用干净的输入和输出进行代码调试。

动机、用例

简短动机

如果您想进行调试,通常您必须选择编写冗长的样板代码(println!)或者拥有需要更多努力才能直观导航的杂乱输出(dbg!)。从干净的输入生成干净输出的能力,使您更容易分析代码并更快地学习。

长动机

如果我们想调试代码,标准库 提供以下选项

print!eprint! 很少被使用,因为用户可以选择 println!eprintln! 来获取相同的结果,但结构更清晰,更容易区分不同的输出(尽管在某些情况下,print!eprint! 可能更可取)。因此,print!eprint! 不是产生最小样板代码的清洁输出的最佳选择。

println!eprintln! 可以生成干净的输出,但它们要求你在输入中编写冗长的样板代码。

dbg! 可以接受干净的输入,但输出杂乱无章,需要更多的努力来直观地导航。

例如,你可能希望从文档和论坛(如 github)中复制代码示例,并将它们粘贴到你的本地环境中(或 Rust Playground)中,以对其进行实验,更好地理解代码的实际功能。我们将演示 println! 的杂乱输入和 dbg! 的杂乱输出是什么样的,并将它们与 printc! 进行比较。

假设你对 Pinning 不熟悉,并阅读了关于它的 文档页面,你遇到了下面的 代码示例

fn main() {
   let mut test1 = Test::new("test1");
   let mut test1_pin = unsafe { Pin::new_unchecked(&mut test1) };
   Test::init(test1_pin.as_mut());

   drop(test1_pin);
   println!(r#"test1.b points to "test1": {:?}..."#, test1.b);

   let mut test2 = Test::new("test2");
   mem::swap(&mut test1, &mut test2);
   println!("... and now it points nowhere: {:?}", test1.b);
}
use std::pin::Pin;
use std::marker::PhantomPinned;
use std::mem;

#[derive(Debug)]
struct Test {
    a: String,
    b: *const String,
    _marker: PhantomPinned,
}


impl Test {
    fn new(txt: &str) -> Self {
        Test {
            a: String::from(txt),
            b: std::ptr::null(),
            // This makes our type `!Unpin`
            _marker: PhantomPinned,
        }
    }

    fn init<'a>(self: Pin<&'a mut Self>) {
        let self_ptr: *const String = &self.a;
        let this = unsafe { self.get_unchecked_mut() };
        this.b = self_ptr;
    }

    #[allow(unused)]
    fn a<'a>(self: Pin<&'a Self>) -> &'a str {
        &self.get_ref().a
    }

    #[allow(unused)]
    fn b<'a>(self: Pin<&'a Self>) -> &'a String {
        assert!(!self.b.is_null(), "Test::b called without Test::init being called first");
        unsafe { &*(self.b) }
    }
}

为了理解代码,你可能会尝试对其进行实验,以用于教育目的。如前所述,println!dbg! 是标准库提供的最佳选项。让我们修改 main() 函数,看看这两种方法各自的运作情况。

println! 方法

杂乱输入

fn main() {
   let mut test1 = Test::new("test1");
   println!("test1 = {:#?}", test1);
   println!();
   
   let mut test1_pin = unsafe { Pin::new_unchecked(&mut test1) };
   Test::init(test1_pin.as_mut());
   
   drop(test1_pin);
   println!("test1 = {:#?}", test1);
   println!();

   let mut test2 = Test::new("test2");
   println!("test1 = {:#?}", test1);
   println!();
   println!("test2 = {:#?}", test2);
   println!();
   
   mem::swap(&mut test1, &mut test2);
   println!("test1 = {:#?}", test1);
   println!();
   println!("test2 = {:#?}", test2);
   println!();
}

整洁输出

test1 = Test {
    a: "test1",
    b: 0x0000000000000000,
    _marker: PhantomPinned,
}

test1 = Test {
    a: "test1",
    b: 0x00007ffd1bdafb68,
    _marker: PhantomPinned,
}

test1 = Test {
    a: "test1",
    b: 0x00007ffd1bdafb68,
    _marker: PhantomPinned,
}

test2 = Test {
    a: "test2",
    b: 0x0000000000000000,
    _marker: PhantomPinned,
}

test1 = Test {
    a: "test2",
    b: 0x0000000000000000,
    _marker: PhantomPinned,
}

test2 = Test {
    a: "test1",
    b: 0x00007ffd1bdafb68,
    _marker: PhantomPinned,
}

dbg! 方法

整洁输入

fn main() {
   let mut test1 = Test::new("test1");
   dbg!(&test1);
   
   let mut test1_pin = unsafe { Pin::new_unchecked(&mut test1) };
   Test::init(test1_pin.as_mut());
   
   drop(test1_pin);
   dbg!(&test1);

   let mut test2 = Test::new("test2");
   dbg!(&test1, &test2);
   
   mem::swap(&mut test1, &mut test2);
   dbg!(&test1, &test2);
}

杂乱输出

[src/main.rs:7] &test1 = Test {
    a: "test1",
    b: 0x0000000000000000,
    _marker: PhantomPinned,
}
[src/main.rs:13] &test1 = Test {
    a: "test1",
    b: 0x00007ffca10e7650,
    _marker: PhantomPinned,
}
[src/main.rs:16] &test1 = Test {
    a: "test1",
    b: 0x00007ffca10e7650,
    _marker: PhantomPinned,
}
[src/main.rs:16] &test2 = Test {
    a: "test2",
    b: 0x0000000000000000,
    _marker: PhantomPinned,
}
[src/main.rs:19] &test1 = Test {
    a: "test2",
    b: 0x0000000000000000,
    _marker: PhantomPinned,
}
[src/main.rs:19] &test2 = Test {
    a: "test1",
    b: 0x00007ffca10e7650,
    _marker: PhantomPinned,
}

printc! 方法

printc! 允许您同时做到输入整洁和输出整洁。

整洁输入

fn main() {
   let mut test1 = Test::new("test1");
   printc!(test1);
   
   let mut test1_pin = unsafe { Pin::new_unchecked(&mut test1) };
   Test::init(test1_pin.as_mut());
   
   drop(test1_pin);
   printc!(test1);

   let mut test2 = Test::new("test2");
   printc!(test1, test2);
   
   mem::swap(&mut test1, &mut test2);
   printc!(test1, test2);
}

整洁输出

test1 = Test {
    a: "test1",
    b: 0x0000000000000000,
    _marker: PhantomPinned,
}

test1 = Test {
    a: "test1",
    b: 0x00007ffd1bdafb68,
    _marker: PhantomPinned,
}

test1 = Test {
    a: "test1",
    b: 0x00007ffd1bdafb68,
    _marker: PhantomPinned,
}

test2 = Test {
    a: "test2",
    b: 0x0000000000000000,
    _marker: PhantomPinned,
}

test1 = Test {
    a: "test2",
    b: 0x0000000000000000,
    _marker: PhantomPinned,
}

test2 = Test {
    a: "test1",
    b: 0x00007ffd1bdafb68,
    _marker: PhantomPinned,
}

无运行时依赖