Rust 在编译时,如何在不知道结构的情况下读取CSV数据?
我是个新手,还没开始尝试实现某种数据库。用户应该通过提供表名、列名向量和列类型向量(通过枚举实现)来创建表。填写表格时应指定csv文件。但是,这需要在编译时指定表行的结构,如基本示例所示:Rust 在编译时,如何在不知道结构的情况下读取CSV数据?,rust,deserialization,Rust,Deserialization,我是个新手,还没开始尝试实现某种数据库。用户应该通过提供表名、列名向量和列类型向量(通过枚举实现)来创建表。填写表格时应指定csv文件。但是,这需要在编译时指定表行的结构,如基本示例所示: #[derive(Debug, Deserialize, Eq, PartialEq)] struct Row { key: u32, name: String, comment: String } use std::error::Error; use csv::ReaderBuild
#[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"))
}
}
#[派生(调试、反序列化、Eq、PartialEq)]
结构行{
关键字:u32,
名称:String,
注释:String
}
使用std::error::error;
使用csv::ReaderBuilder;
使用serde::反序列化;
使用std::fs;
fn从\u文件读取\u(路径:&str)->结果{
让data=fs::read_to_string(path).expect(“无法读取文件”);
让mut rdr=ReaderBuilder::new()
.has_头(false)
.分隔符(b'|')
.from_reader(data.as_bytes());
让mut iter=rdr.deserialize();
如果让一些(结果)=iter.next(){
让记录:行=结果?;
println!(“{:?}”,记录);
好(())
}否则{
Err(From::From(“预期至少有一条记录,但没有记录”))
}
}
是否有可能使用泛型表信息而不是“行”结构来强制转换反序列化的结果?是否可以简单地根据列类型的组合大小分配内存并解析中的记录?我会做这样的事情在C
是否有可能使用泛型表信息而不是“行”结构来强制转换反序列化的结果
所有泛型在编译时都替换为具体类型。如果您不知道运行时需要的类型,“泛型”不是您所需要的
是否可以简单地根据列类型的组合大小分配内存并解析中的记录?我会做这样的事情在C
我建议改为使用Box
,以便能够存储任何类型的引用,并且仍然知道它是什么类型
这种方法的维护成本相当高。您必须在希望使用单元格值的任何位置管理每种可能的值类型。另一方面,您不需要每次都解析值,只需在运行时进行一些类型检查
我使用了std::any::TypeId
来标识类型,但它不能用于match
表达式中。可以考虑使用自定义枚举作为类型标识符。
使用std::any:{any,TypeId};
使用std::io::Read;
使用csv::Reader;
#[衍生(默认)]
结构表{
名称:String,
标题:Vec,
资料来源:Vec,
}
impl表格{
fn添加\头(&mut self,头:字符串,\类型:TypeId){
self.headers.push((header,_-type));
}
fn填充数据(
&莫特·赛尔夫,
rdr:&mut读取器,
)->结果{
对于rdr.records()中的记录{
让记录=记录?;
让mut行:Vec=Vec![];
对于self.headers.iter().zip(record.iter())中的(&(&,type_id),value){
如果type_id==TypeId::of::(){
row.push(Box::new(value.parse::()?);
}如果type_id==TypeId::of::(){
row.push(Box::new(value.to_owned());
}
}
self.data.push(行);
}
好(())
}
}
impl std::fmt::表的显示{
fn-fmt(&self,f:&mut std::fmt::Formatterserde_json有一个通用的值
类型,它提供json的运行时动态构建和映射。有更多的解释。这可能是第一个要研究的方向。您的结果
有一个类型,可以或多或少地作为字符串数组处理。@Jmb没错,我可以存储每一行作为字符串的向量,并在每次访问时转换为实际类型。但是,这似乎不是很有效。因此,您的问题不是关于CSV读取,而是“当类型仅在运行时已知时,如何存储不同类型的值?”然后,您希望对每种可能的类型使用带变体的。由于您是从CSV文件读取,因此您的所有值都将是String
类型。插入时,特定类型可能会发生转换。您可以利用from
特性来实现这一点。例如,如果表a需要值为u32
类型,则您可以可以为u32执行impl From
(这可能已经实现了..不确定)。在插入过程中,您可以执行让值插入到表中。\u A:u32=string\u value.into();
您可以从和中阅读更多关于的信息,这正是我要找的。肯定有“code”这里有开销,但性能可能更好。我计划在标题中的函数指针后面隐藏额外的代码复杂性。通常应尽可能避免使用任何
。如果表只能包含有限的类型集(例如整数、浮点数或字符串),那么最好使用枚举。这避免了间接寻址,允许您简化某些操作(例如,您可以为枚举实现Display
),并确保您不会忘记使用该值的代码中的类型。感谢您的提示。我将尝试这两种方法。