You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 10:03:32