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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 13:53:28