2

考虑这个Config包含结构向量的Host结构:

use serde::Deserialize;
use std::net::IpAddr;

#[derive(Debug, Deserialize)]
struct Config {
    name: String,
    hosts: Vec<Host>
}

#[derive(Debug, Deserialize)]
struct Host {
    addr: IpAddr,
    user: String,
}

使用派生的Deserialize实现,可以使用serde_json和成功反序列化以下 JSON 和 YAML 配置文件serde_yaml

{
  "name": "example",
  "hosts": [
    { "addr": "1.1.1.1", "user": "alice" },
    { "addr": "2.2.2.2", "user": "bob" }
  ]
}
---
name: example
hosts:
  - addr: 1.1.1.1
    user: alice
  - addr: 2.2.2.2
    user: bob

但是,我还希望能够Host从字符串反序列化结构。但是,重要的是我还可以从地图反序列化它,理想情况下,矢量可以由两种格式组成。例如:

{
  "name": "example",
  "hosts": [
    "alice@1.1.1.1",
    { "addr": "2.2.2.2", "user": "bob" }
  ]
}
---
name: example
hosts:
  - alice@1.1.1.1
  - addr: 2.2.2.2
    user: bob

在结构#[serde(try_from = "String")]之上Host,我可以轻松地支持字符串反序列化......但是它不再反序列化地图格式。

serde 网站有一个关于反序列化字符串或结构的页面deserialize_with,但它需要只能应用于字段(而不是结构容器)的属性。我不确定这种技术是否可行,因为我的领域是 aVec<Host>而不仅仅是 a Host

这有可能实现吗?

4

1 回答 1

3

您可以为此使用未标记的枚举。结合自定义反序列化器:

use std::str::FromStr;
use serde::{Deserialize, Deserializer};
use std::net::IpAddr;

#[derive(Debug, Deserialize)]
struct Config {
    name: String,
    hosts: Vec<Host>,
}

#[derive(Debug, Deserialize)]
struct InnerHost {
    addr: IpAddr,
    user: String,
}

#[derive(Debug, Deserialize)]
#[serde(untagged)]
enum Host {
    #[serde(deserialize_with = "deserialize_host_from_str")]
    FromStr(InnerHost),
    FromDict(InnerHost),
}

fn deserialize_host_from_str<'de, D>(deserializer: D) -> Result<InnerHost, D::Error>
where
    D: Deserializer<'de>,
{
    let value = String::deserialize(deserializer)?;
    // parse the value and return host
    Ok(InnerHost {
        addr: IpAddr::from_str("1.1.1.1").unwrap(),
        user: "foobar".to_string(),
    })
}

fn main() {
    let data = r#"{
  "name": "example",
  "hosts": [
    "alice@1.1.1.1",
    { "addr": "2.2.2.2", "user": "bob" }
  ]
}"#;

    let config : Config = serde_json::from_str(data).unwrap();
    println!("{:?}", config);
}

操场

为方便起见,您可以添加for to的AsRefimpl或从枚举中提取它的方法。HostInnerHost

于 2021-10-14T08:08:58.833 回答