如何在Rust中将嵌套结构体序列化为CSV?求可行方案
问题
我尝试将嵌套结构体组成的对象序列化为CSV,嵌套仅用于代码组织,不希望序列化后保留嵌套结构。代码示例如下:
use serde::Serialize; use std::io; #[derive(Serialize)] struct UserInfo { id: String, username: String, } #[derive(Serialize)] struct User { user_info: UserInfo, } fn main() -> Result<(), Box<dyn std::error::Error>> { let mut wtr = csv::Writer::from_writer(io::stdout()); wtr.serialize(User { user_info: UserInfo { id: "1".to_string(), username: "Jon".to_string(), }, })?; wtr.flush()?; Ok(()) }
运行后报错:
Error(Serialize("cannot serialize UserInfo container inside struct when writing headers from structs"))
尝试给user_info添加#[serde(flatten)]属性,但该方式不被rust-csv支持,求可行解决方法,不介意手动添加表头,只希望保留代码中的嵌套结构。
解决方法
方法1:手动实现Serialize trait
直接为User结构体实现Serialize,手动将嵌套的UserInfo字段平铺输出:
use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; use std::io; #[derive(Serialize)] struct UserInfo { id: String, username: String, } struct User { user_info: UserInfo, } impl Serialize for User { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { let mut state = serializer.serialize_struct("User", 2)?; state.serialize_field("id", &self.user_info.id)?; state.serialize_field("username", &self.user_info.username)?; state.end() } } fn main() -> Result<(), Box<dyn std::error::Error>> { let mut wtr = csv::Writer::from_writer(io::stdout()); wtr.serialize(User { user_info: UserInfo { id: "1".to_string(), username: "Jon".to_string(), }, })?; wtr.flush()?; Ok(()) }
方法2:定义平铺DTO结构体并转换
创建一个与CSV列匹配的平结构体,将嵌套的User转换为该DTO后再序列化,既保留原代码的嵌套结构,又能正常输出CSV:
use serde::Serialize; use std::io; #[derive(Serialize)] struct UserInfo { id: String, username: String, } #[derive(Serialize)] struct User { user_info: UserInfo, } #[derive(Serialize)] struct UserCsvDto { id: String, username: String, } impl From<User> for UserCsvDto { fn from(user: User) -> Self { UserCsvDto { id: user.user_info.id, username: user.user_info.username, } } } fn main() -> Result<(), Box<dyn std::error::Error>> { let mut wtr = csv::Writer::from_writer(io::stdout()); let user = User { user_info: UserInfo { id: "1".to_string(), username: "Jon".to_string(), }, }; wtr.serialize(UserCsvDto::from(user))?; wtr.flush()?; Ok(()) }
方法3:手动写入表头与记录
完全手动控制CSV的写入流程,跳过serde的自动序列化,直接写入表头和字段值:
use std::io; #[derive(Debug)] struct UserInfo { id: String, username: String, } #[derive(Debug)] struct User { user_info: UserInfo, } fn main() -> Result<(), Box<dyn std::error::Error>> { let mut wtr = csv::Writer::from_writer(io::stdout()); wtr.write_record(&["id", "username"])?; let user = User { user_info: UserInfo { id: "1".to_string(), username: "Jon".to_string(), }, }; wtr.write_record(&[&user.user_info.id, &user.user_info.username])?; wtr.flush()?; Ok(()) }
内容的提问来源于stack exchange,提问作者diaa
相关产品推荐
相关产品推荐

