使用Serde反序列化CSV时缺失字段无法设为默认值
问题:CSV空字段无法通过
#[serde(default)]设置默认值 我定义了一个用于从字符串反序列化CSV数据的结构体,期望当CSV中up字段为空时,通过#[serde(default)]属性将其设为0.0的默认值,但运行时出现了解析错误。使用up: Option<f64>可以正常运行,但不符合我的数据模型定义,请问问题出在哪里?
测试代码
#[cfg(test)] mod tests { use csv; #[derive(Debug, serde::Deserialize)] struct Test { x: f64, #[serde(default)] up: f64, } #[test] fn deserialise() { let s = "x,up\n0.0,"; let mut rdr = csv::Reader::from_reader(s.as_bytes()); for row in rdr.deserialize() { let option: Test = row.expect("Failure"); dbg!(&option); } } }
报错信息
thread 'tests::deserialise' panicked at 'Failure: Error(Deserialize { pos: Some(Position { byte: 111, line: 2, record: 1 }), err: DeserializeError { field: Some(12), kind: ParseFloat(ParseFloatError { kind: Empty }) } })', data_model\examples\upload_options.rs:80:41
Cargo.toml配置
[package] name = "data_model" version = "0.1.0" edition = "2021" [dependencies] serde = { version = "^1.0", features = ["derive"] } csv = "^1"
解决方法
问题根源
#[serde(default)]仅在字段完全缺失时生效(比如CSV中没有up列,或者某一行未提供该字段的值)。但当CSV中明确存在up字段但值为空字符串时,serde会尝试将空字符串解析为f64,而空字符串无法被解析为浮点数,因此触发ParseFloatError。
解决方案:自定义反序列化逻辑
通过#[serde(deserialize_with)]指定自定义反序列化函数,同时处理空字符串和字段缺失的情况,将其转换为默认值0.0。
修改后的代码如下:
#[cfg(test)] mod tests { use csv; use serde::de::Deserializer; use std::str::FromStr; // 自定义反序列化函数:处理空字符串或缺失字段,返回0.0 fn deserialize_f64_default<'de, D>(deserializer: D) -> Result<f64, D::Error> where D: Deserializer<'de>, { let s: Option<String> = Option::deserialize(deserializer)?; match s.as_deref() { // 空字符串或字段缺失时返回0.0 Some("") | None => Ok(0.0), // 正常解析非空字符串为f64 Some(val) => f64::from_str(val).map_err(serde::de::Error::custom), } } #[derive(Debug, serde::Deserialize)] struct Test { x: f64, // 使用自定义反序列化函数替代单纯的default #[serde(deserialize_with = "deserialize_f64_default")] up: f64, } #[test] fn deserialise() { let s = "x,up\n0.0,"; let mut rdr = csv::Reader::from_reader(s.as_bytes()); for row in rdr.deserialize() { let option: Test = row.expect("Failure"); dbg!(&option); // 输出应为 Test { x: 0.0, up: 0.0 } } } }
补充说明
上述自定义函数同时覆盖了两种场景:当字段缺失时,s会是None,直接返回0.0;当字段存在但为空时,s是Some(""),同样返回0.0,完全符合数据模型的定义要求。
内容的提问来源于stack exchange,提问作者Delta_Fore
相关产品推荐
相关产品推荐

