2016-02-03 9 views
7

は、だから私は、現在、ヒープメモリにYamlファイルをロードすることでstructを初期化するに困惑: ヒープ参照を使用して構造体をイディオムで構築する方法は?

extern crate yaml_rust; 

use std::io::prelude::*; 
use std::fs; 
use yaml_rust::{Yaml, YamlLoader}; 

struct Petrovich { 
    middlename: Yaml, 
    firstname: Yaml, 
    lastname: Yaml 
} 

impl Petrovich { 

    fn new() -> Petrovich { 

     // Open Rules File (Panics on error) 
     let mut f = fs::File::open("./src/rules.yml").unwrap(); 
     // Create String Buffer and Read to it 
     let mut buffer = String::new(); 
     f.read_to_string(&mut buffer).unwrap(); 
     // Pass Buffer to Yaml and unwrap 
     let rules: &Yaml = &YamlLoader::load_from_str(&buffer).unwrap()[0]; 

     // Return Petrovich with preloaded rules 
     Petrovich { 
      middlename: rules["middlename"], 
      firstname: rules["firstname"], 
      lastname: rules["lastname"] 
     } 
    } 
} 

は、しかし、私は cannot move out of indexed contentエラーが発生します。どのように私はこれに取り組んでいますか?

EDIT:https://github.com/Latrasis/petrovich-rs

答えて

2

Yamlは、Cloneです:

Petrovich { 
     middlename: rules["middlename"].clone(), 
     firstname: rules["firstname"].clone(), 
     lastname: rules["lastname"].clone(), 
    } 

データがコピーされているので、私は受け入れられた溶液にこれを好む小さく、それはyaml::Hashの実装に依存しません。ドキュメントツリー全体を複製することも別の問題かもしれません。

ここでyaml-rustに追加する機能があるかもしれません。ツリーから要素を移動することは妥当な要求のようですが、APIはそれを直接サポートしていません。

+0

ありがとうございます!これは実際にはるかに読みやすいです! – latrasis

3

あなたは外に移動しようとしている:./src

ソースがここで見つけることができ以内に、私はこのためyaml-rustを使用してfirstnameを持つファイルrules.ymlを持っています、lastnamemiddlenameフィールドが含ま(rules[str]&Yamlを返すので)借用したポインタですが、それは合法ではありません。メインのYamlオブジェクトから値を移動するための関数を使用する必要があります。これによりメインのYamlオブジェクトが変更されますが、ここでは正常です。関数の最後まで破棄するためです。

まず、文字列によるインデックス付けがどのようなものかを理解する必要があります。 The implementationは、値がハッシュである場合にのみ重要な値を返し、Yaml::String値を構築してハッシュをインデックスすることで基本値に戻ります。

Yaml::HashバリアントはBTreeMap<Yaml, Yaml>をラップします。ライブラリはas_hashの便利な方法でアクセスしますが、これは不変のポインタしか与えません。パターンマッチングを使用して可変ポインタを取得する必要があります。

次に、BTreeMapremove methodを使用して、興味のあるキーに関連付けられた値を抽出します。

ここでの結果です:

impl Petrovich { 
    fn new() -> Petrovich { 
     use yaml_rust::yaml::Hash as YamlHash; 

     // Open Rules File (Panics on error) 
     let mut f = fs::File::open("./src/rules.yml").unwrap(); 
     // Create String Buffer and Read to it 
     let mut buffer = String::new(); 
     f.read_to_string(&mut buffer).unwrap(); 
     // Pass Buffer to Yaml and unwrap 
     let rules: &mut Yaml = &mut YamlLoader::load_from_str(&buffer).unwrap()[0]; 
     let rules: &mut YamlHash = match *rules { 
      Yaml::Hash(ref mut hash) => hash, 
      _ => panic!("not a hash"), 
     }; 

     // Return Petrovich with preloaded rules 
     Petrovich { 
      middlename: rules.remove(&Yaml::String("middlename".into())).unwrap(), 
      firstname: rules.remove(&Yaml::String("firstname".into())).unwrap(), 
      lastname: rules.remove(&Yaml::String("lastname".into())).unwrap(), 
     } 
    } 
} 

注意(それが働いていた場合)、このコードは、元のコード内の状況でパニックになるあなたの代わりにBadValue秒になるだろうと、いないだろうとは。必要に応じてエラーを処理するためにあなたに残しておきます。あなたは、単に「アウト」にその内容をコピーするための基準に)(.cloneを呼び出すことができるように

2

私は最近、YAMLのためSerdeサポートを実装:JSON、YAML、XML、TOML、MessagePack、Bincode:https://github.com/dtolnay/serde-yaml

Serdeは錆の構造体は、様々なフォーマットにしてから変換することを可能にする強力なシリアライゼーション・フレームワークです。ここで

は、ファイルrules.ymlからペトロヴィッチをデシリアライズ実証完全な実施例である:

extern crate serde; 
extern crate serde_yaml; 

#[macro_use] 
extern crate serde_derive; 

#[derive(Deserialize)] 
struct Petrovich { 
    middlename: String, 
    firstname: String, 
    lastname: String 
} 

fn main() { 
    let f = std::fs::File::open("test.yml").unwrap(); 
    let p: Petrovich = serde_yaml::from_reader(f).unwrap(); 
    assert_eq!(&p.firstname, "latrasis"); 
} 

Serdeは、任意に複雑なネストされたタイプをサポートしていますので、あなたがデシリアライズ構造体は、ベクトル、地図、または他のを含めることができます内部の構造体とコードは単純なままです。

+0

これは安定したRustバージョンで動作しますか、または夜間にのみ動作しますか? – rjh

+1

安定した錆1.15以上で動作します。 – dtolnay

関連する問題