Rust中如何实现Field序列化:无doc时省略字段名及换行
问题与解决方案
问题描述
定义了如下Rust结构体:
#[derive(Debug, Serialize)] struct Container { field0: Field<f64>, field1: Field<f64>, } #[derive(Debug, Serialize)] struct Field<T> { val: T, #[serde(skip_serializing_if = "Option::is_none")] doc: Option<String>, }
对于以下实例:
Container { field0: Field { val: 1.5, doc: Some("my documentation!") }, field1: Field { val: 2.0, doc: None } }
期望得到的YAML输出为:
field0: val: 1.5 doc: my documentation! field1: 2.0
但默认派生的Serialize实现生成的结果不符合预期:
field0: val: 1.5 doc: my documentation! field1: val: 2.0
自行实现Serialize时因写法错误,得到了带空键的错误输出:
field0: val: 1.5 doc: my documentation! field1: '': 2.0
正确实现方式
核心问题是当doc为None时,不应继续按结构体序列化,而是直接序列化val的值。修改后的Serialize实现如下:
impl<T> Serialize for Field<T> where T: Serialize { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { if let Some(doc) = &self.doc { // 存在doc时,序列化完整结构体 let mut state = serializer.serialize_struct("Field", 2)?; state.serialize_field("val", &self.val)?; state.serialize_field("doc", doc)?; state.end() } else { // doc为None时,直接序列化val的值 self.val.serialize(serializer) } } }
此实现会让field1直接输出2.0,完全符合预期格式。
更简洁的方案
若不想手动实现Serialize,可借助serde的枚举+#[serde(untagged)]特性实现类似效果。将Field改为枚举:
#[derive(Debug, Serialize)] #[serde(untagged)] enum Field<T> { WithDoc { val: T, doc: String }, WithoutDoc(T), }
使用时需调整实例构造方式:
Container { field0: Field::WithDoc { val: 1.5, doc: "my documentation!".to_string() }, field1: Field::WithoutDoc(2.0) }
这种方式无需手动实现Serialize,但需要修改Field的定义和使用逻辑,适合愿意调整数据结构的场景。
内容的提问来源于stack exchange,提问作者Kyle Carow
相关产品推荐
相关产品推荐

