颠覆Rust的类型系统,用于printf式调试

xrl*_*xrl 3 serialization types rust

我正在进行serde Serializer实现,我想在机器深处调试值.也就是说,我想调试传递给序列序列化器的值 - 我想用我cargo test当前被序列化的值炸出我的运行.

fn serialize_seq_elt<T>(&mut self, value: T) -> Result<(), Self::Error> where T: Serialize {
    Err(CdrError{
        reason: format!("{:?}", value)
    })
//        value.serialize(self) // previous, type checked-code
}
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,我在编译时遇到错误:

   Compiling rtps v0.1.0 (file:///Users/xavierlange/code/dds/rtps)
src/cdr/ser.rs:98:37: 98:42 error: the trait bound `T: std::fmt::Debug` is not satisfied [E0277]
src/cdr/ser.rs:98             reason: format!("{:?}", value)
                                                      ^~~~~
Run Code Online (Sandbox Code Playgroud)

这是真的,serde Serializer不强制Debug性格.是否有宏观或其他方式来解决它?我是否需要破解serde库以添加相关特征?

Dog*_*ert 5

您可以使用newtype和specialized执行此操作,如下所示:

#![feature(specialization)]

use std::fmt;

struct TryDebug<T>(T);

impl<T> fmt::Debug for TryDebug<T> {
    default fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "no std::fmt::Debug impl")
    }
}

impl<T: fmt::Debug> fmt::Debug for TryDebug<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.0.fmt(f)
    }
}

struct Foo;

fn main() {
    println!("{:?}", TryDebug(1));
    println!("{:?}", TryDebug("foo"));
    println!("{:?}", TryDebug(Foo));
}
Run Code Online (Sandbox Code Playgroud)

输出:

1
"foo"
no std::fmt::Debug impl
Run Code Online (Sandbox Code Playgroud)

注意:从今天开始,专业化是一项不稳定的功能.你必须使用Rust Nightly来实现这个目的.

  • 哦,这是一个非常有趣的通用解决方案 (2认同)
  • 一个明显的缺点是你需要一个newtype包装器.我认为使用它并不总是可行或方便的. (2认同)