我有大约10个结构,每个结构有5-10个字段,我希望能够使用相同的格式将它们打印出来。
我的大多数结构看起来像这样:
struct Example {
a: Option<String>,
b: Option<i64>,
c: Option<String>,
... etc
}我希望能够为fmt::Display定义一个impl,而不必再次枚举字段,这样如果添加了一个新字段,就不会遗漏一个。
对于结构:
let eg = Example{
a: Some("test".to_string),
b: Some(123),
c: None,
}我想要输出格式:
a: test
b: 123
c: -我目前使用的是#[derive(Debug)],但我不喜欢它打印出Some(X)和None以及其他一些东西。
如果我知道我的结构中的所有值都是Option<T: fmt::Display>的,那么我可以生成一个Display方法而不必再次列出这些字段吗?
发布于 2019-10-23 11:07:40
这可能不是最小的实现,但您可以派生serialisable并使用serde机箱。下面是一个自定义序列化程序的示例:https://serde.rs/impl-serializer.html
在您的情况下,它可能要简单得多(您只需要少数几个类型,并且可以在任何意想不到的情况下恐慌/忽略)。
另一种方法是编写宏并创建自己的轻量级序列化解决方案。
发布于 2019-10-24 04:25:55
我最终用宏解决了这个问题。虽然它不是理想的,但它可以完成这项工作。
我的宏目前看起来像这样:
macro_rules! MyDisplay {
($struct:ident {$( $field:ident:$type:ty ),*,}) => {
#[derive(Debug)]
pub struct $struct { pub $($field: $type),*}
impl fmt::Display for $struct {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
$(
write!(f, "{}: {}\n",
stringify!($field).to_string(),
match &self.$field {
None => "-".to_string(),
Some(x) => format!("{:#?}", x)
}
)?;
)*
Ok(())
}
}
};
}它可以像这样使用:
MyDisplay! {
Example {
a: Option<String>,
b: Option<i64>,
c: Option<String>,
}
}我的宏是基于Cerberus提供的这里的https://stackoverflow.com/a/54177889/1355121
https://stackoverflow.com/questions/58514822
复制相似问题