我希望能够读取包含下划线的整数(千位分隔符)
- instrument: 5_000_000
other_field: this string contains an _
- instrument: 5_000_000
other_field: this string contains an _
Run Code Online (Sandbox Code Playgroud)
使用 serde_yaml 这怎么可能?
正如我在评论中所说,就 yaml 反序列化器而言,文本“5_000_000”始终是字符串,而不是整数。所以你需要告诉serde这个领域需要特殊对待。您可以按照注释中的描述创建一个FooSerialized结构(这会重复很多定义),或者使用该deserialize_with属性来自定义字段反序列化:
use serde::{de, Deserialize};
#[derive(Deserialize, Debug)]
pub struct Foo {
#[serde(deserialize_with = "deserialize_underscored_integer")]
pub instrument: u64,
pub other_field: String,
}
fn deserialize_underscored_integer<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
D: de::Deserializer<'de>,
T: std::str::FromStr,
{
// First, deserialize the value as a string (which might fail...)
let s: String = de::Deserialize::deserialize(deserializer)?;
// next, filter out the underscores (and invalid chars while we are at it),
// collect the remaining chars into a new string, parse that as an integer
// and return that
s.chars()
.filter_map(|c| match c {
c @ '0'..='9' => Some(Ok(c)),
'_' => None,
_ => Some(Err(de::Error::custom("invalid char in string"))),
})
.collect::<Result<String, _>>()?
.parse()
.map_err(|_: <T as std::str::FromStr>::Err| {
de::Error::custom("string does not represent an integer")
})
}
fn main() {
// This will succeed
let inp = r#"
- instrument: 1_2_34_567_8_9____0
other_field: this string contains an _
- instrument: 5_000_000
other_field: this string contains an _
"#;
println!("{:?}", serde_yaml::from_str::<Vec<Foo>>(inp).unwrap());
// This will fail because its not a integer
let inp = r#"
- instrument: 5000 abcdef
other_field: this string contains some other stuff
"#;
println!("{:?}", serde_yaml::from_str::<Vec<Foo>>(inp).unwrap_err());
// This looks like an integer but is not a u64
let inp = r#"
- instrument: 5_000_000_000_000_000_000_000
other_field: this string is too large to be a u64
"#;
println!("{:?}", serde_yaml::from_str::<Vec<Foo>>(inp).unwrap_err());
}
Run Code Online (Sandbox Code Playgroud)