2017-12-13 21 views
1

config-rsを使用してTOMLファイルから設定をロードしています。列をデニール化してenumにしたいとします。私はdeserialize_with serde_deriveの機能を使って解決しようとしましたが、関数の署名を満たすのに適切なErrorを返す方法がわかりません。どうすれば達成できますか?config-rsを使用してTOML文字列をenumにデシリアライズ

私の依存関係:列挙型RotationPolicyTypeをデシリアライズすることを意図しています

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

コード例:と

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_with

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_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 
+0

*私は*成功しなかった - なぜあなたは成功しませんでしたどのように表示されませんでしたか?コードはコンパイルされませんか?コードは期待どおりに機能しませんか?何が起こった?どのTOMLファイルを解読しようとしましたか? – Shepmaster

+0

コメントありがとうございます。私の試みで質問を更新してください。 – cspinetta

+1

Serde自体に[ここで期待されるものの例](https://github.com/serde-rs/serde/blob/master/serde/src/de/mod.rs#L262)があります。具体的には、あなたは 'Error :: custom(....)'を使いたいと思うようです。 –

答えて

3

まず、あなたの例では、十分にあなたが記述されているエラーを取得するためにコンパイルされません。次回はMCVEを作成してください。 https://play.rust-lang.orgで動作させるためのボーナスポイント(これは可能ですが、extern crate configはあなたの例では全く必要ありません)。

すべてのコンパイルの問題を修正した後、あなたの最初のエラーは単に1に一致するように機能するAPIを変更することで固定されているが、エラーがあなたを助けようとしたin the serde docs

-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です。 DDeserializer<'de>を実装する場合にのみ可能なのはどれですか。しかし、&'de mut DDeserializer<'de>を実装しています。この問題に対する解決策を見つけることは、読者の練習として残されています。解決策は非常に簡単だったの@ OLI-OBK-KERのアドバイスに従い

+0

Settings :: new()に示すようにconfig :: Configを使用するには、crate * config *が必要です。クレート設定を持たないので、再生中に再現することはできませんが、エラーを再現するためにコードを変更する必要はありません。どのような問題を修正しなければなりませんでしたか? – cspinetta

+0

@oli_obk_kerあなたのアドバイスに本当に感謝しています。私は一生遊んで失ってしまい、参照によってデシリアライザを渡してしまい、結局解決はかなり簡単でした。また、IDEAは 'serde :: de :: Error :: custom'の可視性について私に騙されました。とにかく、ありがとうございます!同じ問題を抱えている人と共有するためのソリューションを投稿します。 – cspinetta

+1

遊び場での再生:https://play.rust-lang.org/?gist=ca29c20db012f5688204a62631b5d218&version=stableあなたのreproには 'new'メソッドは必要ありません;) –

0

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() 
    } 
} 
関連する問題