我需要从一个字符串中反序列化多个结构,该字符串是一串带有键值对的线,这些键值对代表该结构的属性。
示例
field1=something
field2=556
field3=true
field4=10.0.0.1
每个字段的类型将始终相同,但并不总是存在。顺序也可以更改。
struct Data {
field1: Option<String>,
field2: Option<u32>,
field3: Option<bool>,
field4: Option<std::net::Ipv4Addr>
}
做到这一点的最佳方法是什么?我应该使用serde
板条箱吗?
我知道我可以像这样手动进行操作(请参见https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e16244e50492aa218217cb44d5f27cfe)
但是我如何针对多个结构将其通用化?
use std::net::Ipv4Addr;
use std::str::FromStr;
#[derive(Debug)]
struct Data {
field1: Option<String>,
field2: Option<u32>,
field3: Option<bool>,
field4: Option<Ipv4Addr>,
}
fn main() {
let mut s = "field1=something
field2=556
field3=true
field4=10.0.0.1"
.to_string();
let mut field1 = None;
let mut field2 = None;
let mut field3 = None;
let mut field4 = None;
let lines: Vec<_> = s.split("\n").collect();
for line in lines {
let pair: Vec<_> = line.splitn(2, "=").collect();
let key = pair[0];
let value = pair[1];
match key {
"field1" => {
field1 = Some(value.to_owned());
}
"field2" => {
field2 = Some(u32::from_str(value).unwrap());
}
"field3" => {
field3 = match value {
"true" => Some(true),
"false" => Some(false),
_ => None
};
}
"field4" => {
field4 = Some(Ipv4Addr::from_str(value).unwrap());
}
_ => {}
}
}
println!(
"{:?}",
Data {
field1,
field2,
field3,
field4
}
);
}
答案 0 :(得分:2)
概括多个目标结构的一种方法可能是使用serde。
如果是自定义格式,则必须实施反序列化程序, 但不是这样的实现 当自定义格式是标准格式的子集或与标准格式相似时,值得考虑使用社区支持的数据格式。
您的格式似乎是TOML格式的子集:如果是这种情况,请使用toml。
#[macro_use]
extern crate serde_derive;
#[derive(Serialize, Deserialize, Debug)]
struct Data {
field1: Option<String>,
field2: Option<u32>,
field3: Option<bool>,
field4: Option<std::net::Ipv4Addr>
}
fn main() {
let serialized = r#"
field1="something"
field2=556
field3=true
field4="10.0.0.1"
"#;
let deserialized: Data = toml::from_str(&serialized).unwrap();
println!("{:?}", deserialized);
}
如果您的格式不完全是“标准”兼容格式,请在反序列化之前寻找一种转换编码数据的方法:例如,如果field1
和field4
不是用基于regex的引号引起来的字符串模式替换可能有效:
#[macro_use]
extern crate serde_derive;
use std::borrow::Cow;
use regex::{Captures, Regex};
#[derive(Serialize, Deserialize, Debug)]
struct Data {
field1: Option<String>,
field2: Option<u32>,
field3: Option<bool>,
field4: Option<std::net::Ipv4Addr>,
}
fn reformat_string(before: &str) -> Cow<str> {
let matcher : Regex = Regex::new(
r"(?P<f>field1|field4)=(?P<val>[\w.]+)"
).unwrap();
matcher.replace_all(before, |cap: &Captures| {
let mut buff = String::new();
if &cap[1] == "field1" || &cap[1] == "field4" {
cap.expand("$f='$val'", &mut buff);
}
Cow::Owned(buff)
})
}
fn main() {
let serialized = r#"
field1=something
field2=556
field3=true
field4=10.0.0.1
"#;
let transformed = reformat_string(serialized);
let deserialized: Data = toml::from_str(&transformed).unwrap();
println!("{:?}", deserialized);
}