所以我目前通过将struct
文件加载到堆内存中而难以初始化Yaml
:
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
错误。我该如何解决这个问题?
编辑:我正在使用yaml-rust
,并在rules.yml
中包含firstname
,lastname
和middlename
字段的文件./src
答案 0 :(得分:3)
您正试图摆脱借来的指针(因为rules[str]
返回&Yaml
),但这不合法。我们需要使用允许我们将值移出主Yaml
对象的函数。这将改变主Yaml
对象,但这可以,因为我们将在函数结束时丢弃它。
首先,我们需要了解字符串索引的作用。如果值是哈希值,则The implementation仅返回一个重要值,并通过构造Yaml::String
值来索引哈希值来获取基础值。
Yaml::Hash
变体包裹BTreeMap<Yaml, Yaml>
。该库提供了as_hash
便捷方法来访问它,但这只提供了一个不可变的指针。我们需要使用模式匹配来获取可变指针。
接下来,我们将使用BTreeMap
上的remove
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
。我会留给你处理你需要的错误。
答案 1 :(得分:2)
Yaml
是Clone
,因此您只需在引用上调用.clone()即可复制其内容&#34; out&#34;:
Petrovich {
middlename: rules["middlename"].clone(),
firstname: rules["firstname"].clone(),
lastname: rules["lastname"].clone(),
}
我更喜欢这个被接受的解决方案,因为被复制的数据很小,并且它不依赖于yaml::Hash
的实现。克隆整个文档树可能是另一回事。
这里可能有一个参数可以添加到yaml-rust中。将元素移出树是一个合理的请求,但API不直接支持它。
答案 2 :(得分:2)
我最近对YAML实施了Serde支持:https://github.com/dtolnay/serde-yaml
Serde是一个功能强大的序列化框架,允许将Rust结构转换为各种格式:JSON,YAML,XML,TOML,MessagePack,Bincode。
这是一个完整的工作示例,演示了从文件rules.yml反序列化Petrovich:
Comment
Serde支持任意复杂的嵌套类型,因此反序列化的结构可以包含向量,映射或其他结构,代码将保持简单。