4

我正在使用 config-rs 从 TOML 文件加载配置,并且我想将字符串反序列化为枚举。我尝试使用deserialize_withserde_derive 的功能来解决它​​,但我不知道如何返回合适的错误来满足函数签名。我怎样才能实现它?

我的依赖:

config = "0.7"
serde_derive = "1.0"
serde = "1.0"
toml = "0.4"

用于反序列化 enum 的示例代码RotationPolicyType

extern crate config;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate toml;

use std::env;
use config::{Config, Environment, File};
use std::path::PathBuf;
use serde;
use serde::de::Deserializer;
use serde::Deserialize;

#[derive(Debug, Deserialize, Clone)]
pub enum RotationPolicyType {
    ByDuration,
    ByDay,
}

#[derive(Debug, Deserialize, Clone)]
pub struct FileConfig {
    pub rotations: i32,
    #[serde(deserialize_with="deserialize_with")]
    pub rotation_policy_type: RotationPolicyType,
}

#[derive(Debug, Deserialize, Clone)]
pub struct Settings {
    pub threads: usize,
    pub file_writer: FileConfig,
}

impl Settings {
    pub fn new() -> Self {
        let mut s = Config::new();
        s.merge(File::with_name("config/default")).unwrap();
        s.merge(File::with_name("config/local").required(false))
            .unwrap();
        s.merge(Environment::with_prefix("app")).unwrap();
        s.deserialize().unwrap()
    }
}


fn deserialize_with<D>(deserializer: D) -> Result<RotationPolicyType, D::Error> where D: Deserializer {
    let s = String::deserialize(deserializer)?;

    match s.as_ref() {
        "ByDuration" => Ok(RotationPolicyType::ByDuration),
        "ByDay" => Ok(RotationPolicyType::ByDay),
        _ => Err(serde::de::Error::custom("error trying to deserialize rotation policy config"))
    }
}



fn deserialize_with2<'de, D>(deserializer: &'de mut D) -> Result<RotationPolicyType, D::Error> where &'de mut D: Deserializer<'de> {
    let s = String::deserialize(deserializer)?;

    match s.as_ref() {
        "ByDuration" => Ok(RotationPolicyType::ByDuration),
        "ByDay" => Ok(RotationPolicyType::ByDay),
        _ => Err(serde::de::Error::custom("error trying to deserialize rotation policy config"))
    }
}

deserialize_with编译错误:

error[E0106]: missing lifetime specifier
  --> src/settings.rs:30:94
   |
30 |     fn deserialize_with<D>(deserializer: D) -> Result<RotationPolicyType, D::Error> where D: Deserializer {
   |                                                                                              ^^^^^^^^^^^^ expected lifetime parameter

error: aborting due to previous error

deserialize_with2的编译错误:

error[E0220]: associated type `Error` not found for `D`
  --> src/settings.rs:42:90
   |
42 |     fn deserialize_with2<'de, D>(deserializer: &'de mut D) -> Result<RotationPolicyType, D::Error> where &'de mut D: Deserializer<'de> {
   |                                                                                          ^^^^^^^^ associated type `Error` not found

error: aborting due to previous error
4

2 回答 2

3

首先,您的示例编译得不够远,无法解决您描述的错误。请注意下次制作MCVE 。让它在https://play.rust-lang.org上工作的奖励积分(这是可能的,extern crate config在你的例子中完全没有必要)。

修复所有编译问题后,您的第一个错误只需更改函数 API 以匹配serde 文档中建议的错误即可

-fn deserialize_with<     D>(deserializer: D) -> Result<RotationPolicyType, D::Error> where D: Deserializer
+fn deserialize_with<'de, D>(deserializer: D) -> Result<RotationPolicyType, D::Error> where D: Deserializer<'de>

该错误试图帮助您。它告诉您Deserializer缺少生命周期参数。

第二个函数告诉你D没有关联的类型Error。它只有在D实施时才能拥有Deserializer<'de>。但是您指定了&'de mut D实现Deserializer<'de>. 找到这个问题的解决方案留给读者作为练习。

于 2017-12-13T07:54:35.973 回答
1

遵循@oli-obk-ker 的建议,解决方案非常简单:

use std::env;
use config::{Config, File, Environment};
use std::path::PathBuf;
use serde;
use serde::de::Deserializer;
use serde::Deserialize;

pub trait DeserializeWith: Sized {
    fn deserialize_with<'de, D>(de: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>;
}

#[derive(Debug, Deserialize, Eq, PartialEq, Clone)]
pub enum RotationPolicyType {
    ByDuration,
    ByDay
}

impl DeserializeWith for RotationPolicyType {
    fn deserialize_with<'de, D>(de: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
        let s = String::deserialize(de)?;

        match s.as_ref() {
            "ByDuration" => Ok(RotationPolicyType::ByDuration),
            "ByDay" => Ok(RotationPolicyType::ByDay),
            _ => Err(serde::de::Error::custom("error trying to deserialize rotation policy config"))
        }
    }
}

#[derive(Debug, Deserialize, Clone)]
pub struct FileConfig {
    pub rotations: i32,
    #[serde(deserialize_with="RotationPolicyType::deserialize_with")]
    pub rotation_policy_type: RotationPolicyType,
}

#[derive(Debug, Deserialize, Clone)]
pub struct Settings {
    pub threads: i32,
    pub file_writer: FileConfig,
}

impl Settings {
    pub fn new() -> Self {
        let mut s = Config::new();
        s.merge(File::with_name("config/default")).unwrap();
        s.merge(File::with_name("config/local").required(false)).unwrap();
        s.merge(Environment::with_prefix("app")).unwrap();
        s.deserialize().unwrap()
    }
}
于 2017-12-13T14:31:38.440 回答