如何解决如何在不知道编译时结构的情况下读取CSV数据?
我对Rust还是很陌生,并试图实现某种数据库。用户应通过提供一个表名,一个列名向量和一个列类型向量(通过枚举实现)来创建表。填写表格应通过指定csv文件来完成。但是,这要求在编译时指定表行的结构,如基本示例所示:
#[derive(Debug,Deserialize,Eq,PartialEq)]
struct Row {
key: u32,name: String,comment: String
}
use std::error::Error;
use csv::ReaderBuilder;
use serde::Deserialize;
use std::fs;
fn read_from_file(path: &str) -> Result<(),Box<dyn Error>> {
let data = fs::read_to_string(path).expect("Unable to read file");
let mut rdr = ReaderBuilder::new()
.has_headers(false)
.delimiter(b'|')
.from_reader(data.as_bytes());
let mut iter = rdr.deserialize();
if let Some(result) = iter.next() {
let record:Row = result?;
println!("{:?}",record);
Ok(())
} else {
Err(From::from("expected at least one record but got none"))
}
}
是否可以使用通用表信息代替“行”结构来进行反序列化的结果转换?是否可以根据列类型的组合大小简单地分配内存并解析其中的记录?我会在C中做这样的事情...
解决方法
是否可以使用通用表信息代替“行”结构来进行反序列化的结果转换?
在编译时将所有泛型替换为具体类型。如果您不知道运行时所需的类型,则不需要“泛型”。
是否可以根据列类型的组合大小简单地分配内存并解析其中的记录?我会在C中做这样的事情...
我建议改用Box<dyn Any>
,以便能够存储任何类型的引用,并且仍然知道它是什么类型。
此方法的维护成本非常高。您必须在要使用单元格值的任何地方管理每种可能的值类型。另一方面,您不需要每次都解析值,只需在运行时进行一些类型检查即可。
我已经使用std::any::TypeId
来标识类型,但是不能在match
表达式中使用它。您可以考虑使用自定义枚举作为类型标识符。
use std::any::{Any,TypeId};
use std::io::Read;
use csv::Reader;
#[derive(Default)]
struct Table {
name: String,headers: Vec<(String,TypeId)>,data: Vec<Vec<Box<dyn Any>>>,}
impl Table {
fn add_header(&mut self,header: String,_type: TypeId) {
self.headers.push((header,_type));
}
fn populate_data<R: Read>(
&mut self,rdr: &mut Reader<R>,) -> Result<(),Box<dyn std::error::Error>> {
for record in rdr.records() {
let record = record?;
let mut row: Vec<Box<dyn Any>> = vec![];
for (&(_,type_id),value) in self.headers.iter().zip(record.iter()) {
if type_id == TypeId::of::<u32>() {
row.push(Box::new(value.parse::<u32>()?));
} else if type_id == TypeId::of::<String>() {
row.push(Box::new(value.to_owned()));
}
}
self.data.push(row);
}
Ok(())
}
}
impl std::fmt::Display for Table {
fn fmt(&self,f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f,"Table: {}",self.name)?;
for (name,_) in self.headers.iter() {
write!(f,"{},",name)?;
}
writeln!(f)?;
for row in self.data.iter() {
for cell in row.iter() {
if let Some(&value) = cell.downcast_ref::<u32>() {
write!(f,value)?;
} else if let Some(value) = cell.downcast_ref::<String>() {
write!(f,value)?;
}
}
writeln!(f)?;
}
Ok(())
}
}
fn main() {
let mut table: Table = Default::default();
table.name = "Foo".to_owned();
table.add_header("key".to_owned(),TypeId::of::<u32>());
table.add_header("name".to_owned(),TypeId::of::<String>());
table.add_header("comment".to_owned(),TypeId::of::<String>());
let data = "\
key,name,comment
1,foo,foo comment
2,bar,bar comment
";
let mut rdr = Reader::from_reader(data.as_bytes());
table.populate_data(&mut rdr).unwrap();
print!("{}",table);
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。