如何在Rust中无需手动转换将多字段结构体写入Excel?
Rust 中无需手动转换结构体即可写入 Excel 的方案
方案1:rust_xlsxwriter 结合 serde 自动处理转换
rust_xlsxwriter 本身没有原生支持结构体直接写入,但可以借助 serde 的序列化能力,自动提取结构体字段和值,避免手动逐个转换。
示例代码:
use rust_xlsxwriter::{Workbook, Worksheet, Format}; use serde::Serialize; use serde_json::Value; #[derive(Serialize)] struct User { id: u32, name: String, email: String, age: u8, // 可添加任意数量字段 } // 将结构体转为值列表 fn struct_to_values<T: Serialize>(item: &T) -> Vec<Value> { let json = serde_json::to_value(item).unwrap(); if let Value::Object(obj) = json { obj.into_values().collect() } else { Vec::new() } } // 获取结构体字段名作为表头 fn get_struct_fields<T: Serialize>() -> Vec<String> { let dummy = std::mem::MaybeUninit::<T>::uninit(); let json = serde_json::to_value(unsafe { dummy.assume_init_ref() }).unwrap(); if let Value::Object(obj) = json { obj.keys().cloned().collect() } else { Vec::new() } } fn main() { let mut workbook = Workbook::new(); let mut worksheet = workbook.add_worksheet(); // 准备测试数据 let users = vec![ User { id: 1, name: "Alice".into(), email: "alice@example.com".into(), age: 30 }, User { id: 2, name: "Bob".into(), email: "bob@example.com".into(), age: 25 }, ]; // 写入表头 let headers = get_struct_fields::<User>(); for (col, header) in headers.iter().enumerate() { worksheet.write(0, col as u16, header).unwrap(); } // 写入行数据 for (row_idx, user) in users.iter().enumerate() { let values = struct_to_values(user); for (col_idx, value) in values.iter().enumerate() { match value { Value::Number(n) => { if let Some(u) = n.as_u64() { worksheet.write(row_idx as u16 +1, col_idx as u16, u).unwrap(); } else if let Some(f) = n.as_f64() { worksheet.write(row_idx as u16 +1, col_idx as u16, f).unwrap(); } } Value::String(s) => worksheet.write(row_idx as u16 +1, col_idx as u16, s).unwrap(), Value::Bool(b) => worksheet.write(row_idx as u16 +1, col_idx as u16, b).unwrap(), _ => {} } } } workbook.save("users.xlsx").unwrap(); }
方案2:正确使用 Polars 转换结构体
你之前的 Polars 操作大概率是依赖特性没加全,或者转换方法用错了。Polars 支持通过 serde 直接将结构体集合转为 DataFrame,再写入 Excel。
示例代码:
use polars::prelude::*; use serde::Serialize; #[derive(Debug, Clone, Serialize)] struct Product { id: u32, name: String, price: f64, in_stock: bool, } fn main() { let products = vec![ Product { id: 1, name: "Laptop".into(), price: 999.99, in_stock: true }, Product { id: 2, name: "Mouse".into(), price: 25.50, in_stock: false }, ]; // 结构体 Vec 转 DataFrame let df = DataFrame::from_iter(products).unwrap(); // 写入 Excel df.write_excel("products.xlsx").unwrap(); }
需要在 Cargo.toml 中添加带 excel 特性的 Polars 依赖:
polars = { version = "0.35", features = ["serde", "excel", "lazy"] }
方案3:用 excel-writer 直接映射结构体
excel-writer 提供了自定义派生宏,可直接将结构体转为 Excel 行,还支持自定义表头名称,完全无需手动转换。
示例代码:
use excel_writer::{ExcelWriter, StructExcel}; #[derive(Debug, StructExcel)] struct Order { #[excel(header = "订单ID")] order_id: u64, #[excel(header = "客户名称")] customer_name: String, #[excel(header = "订单金额")] amount: f64, #[excel(header = "是否完成")] is_completed: bool, } fn main() { let orders = vec![ Order { order_id: 1001, customer_name: "张三".into(), amount: 150.0, is_completed: true }, Order { order_id: 1002, customer_name: "李四".into(), amount: 200.5, is_completed: false }, ]; let mut writer = ExcelWriter::new(); writer.add_sheet("订单数据", &orders).unwrap(); writer.save("orders.xlsx").unwrap(); }
内容的提问来源于stack exchange,提问作者Mikhail Subbotin
相关产品推荐
相关产品推荐

