如何用Rust的serde和csv crate实现嵌套JSON转带前缀的CSV?
解决方案
要实现嵌套结构体序列化CSV时自动扁平化并添加前缀,最便捷的方式是借助serde_with第三方 crate,无需手动实现完整序列化器。
方法一:使用serde_with的FlattenPrefix
- 首先在
Cargo.toml中添加依赖:
[dependencies] serde = { version = "1.0", features = ["derive"] } csv = "1.2" serde_with = "3.0"
- 修改结构体定义,通过
serde_as和FlattenPrefix属性实现带前缀的扁平化:
use serde::Serialize; use serde_with::{serde_as, FlattenPrefix}; #[serde_as] #[derive(Serialize)] struct Foo { // 给Bar的所有字段添加"bar_"前缀并扁平化 #[serde_as(as = "FlattenPrefix<'bar_>")] bar: Bar, } #[derive(Serialize)] struct Bar { baz: String, qux: String, }
- 序列化到CSV的示例代码:
use csv::Writer; fn main() -> Result<(), Box<dyn std::error::Error>> { let foo = Foo { bar: Bar { baz: "test_baz".to_string(), qux: "test_qux".to_string(), }, }; let mut writer = Writer::from_writer(std::io::stdout()); writer.serialize(foo)?; writer.flush()?; Ok(()) }
执行后输出的CSV表头为bar_baz,bar_qux,字段值也会对应填充,完全符合需求。这种方式不会影响原结构体的反序列化逻辑,适合大型JSON解析流程。
方法二:手动定义CSV专用结构体(无额外依赖)
如果不想引入第三方 crate,可以专门定义用于CSV序列化的结构体,将嵌套字段展开,再实现原结构体到该结构体的转换:
use serde::Serialize; // 原结构体,保持原有反序列化逻辑 struct Foo { bar: Bar, } struct Bar { baz: String, qux: String, } // 用于CSV序列化的扁平化结构体 #[derive(Serialize)] struct FooCsv { bar_baz: String, bar_qux: String, } // 实现从Foo到FooCsv的转换 impl From<Foo> for FooCsv { fn from(foo: Foo) -> Self { FooCsv { bar_baz: foo.bar.baz, bar_qux: foo.bar.qux, } } }
序列化时只需将Foo实例转换为FooCsv再传入CSV writer即可。这种方式适合结构体数量较少的场景,但需要维护额外的转换逻辑。
内容的提问来源于stack exchange,提问作者Benjamin Peinhardt
相关产品推荐
相关产品推荐

