我正在用 Rust 开发一个单词生成器。该应用程序由两个主要结构组成:Letter和Alphabet.
Letter 由单个字符和有关其与其他字母关系的规则组成。
Alphabet包含元音和辅音的向量以及引用这些向量中字母的哈希图。这样做是为了可以在 O(1) 时间内检索字母的规则。
我创建了一个工厂方法来从 json 字符串(下面的代码)中读取字母表,但是我收到一个错误,指出字母表实例的寿命不够长。
src/word_generator/alphabet.rs:47:6: 47:14 错误:
alphabet寿命不够长 src/word_generator/alphabet.rs:47alphabet.add_letter(letter);src/word_generator/alphabet.rs:26:40: 55:3 注意:参考必须对 26:39 在块上定义的匿名生命周期 #1 有效... src/word_generator/alphabet.rs:26 pub fn from_json (json: &str)->字母{
注意:...但借用的值仅对 40:37 src/word_generator/alphabet.rs:40 处的语句 3 后面的块后缀有效 let mut episode = Alphabet::new(); src/word_generator/alphabet.rs:41
我理解错误(我希望),但我不明白它为什么会发生。为什么Alphabet函数返回的 实例new()被变量借用了alphabet?这不是移动操作吗?
pub struct Alphabet<'a>{
pub vowels: Vec<Letter>,
pub consonants: Vec<Letter>,
letters: HashMap<char,&'a Letter>
}
impl<'a> Alphabet<'a>{
pub fn new()->Alphabet<'a>{
return Alphabet{
vowels: Vec::new(),
consonants: Vec::new(),
letters: HashMap::new()
}
}
pub fn from_json(json: &str)->Alphabet{
let data :Json = match Json::from_str(json){
Ok(_data)=>_data,
Err(_err)=>panic!("Invalid JSON provided")
};
let letters = match data.as_array(){
Some(_letters)=>_letters,
None=>panic!("Expected JSON\'s root to be an array but found a different structure.")
};
let mut it = letters.iter();
let mut alphabet = Alphabet::new();
loop {
match it.next(){
Some(x) =>{
let letter : Letter= json::decode(&(x.to_string())).unwrap();
alphabet.add_letter(letter);
},
None => break,
}
}
return alphabet
}
fn add_letter(&'a mut self,ref l: Letter){
match l.letter_type {
LetterType::Vowel =>{
self.vowels.push(l.clone());
self.letters.insert(l.value, &self.vowels.last().unwrap());
},
LetterType::Consonant =>{
self.consonants.push(l.clone());
self.letters.insert(l.value, &self.consonants.last().unwrap());
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
PS:我对 Rust 很陌生,因此非常欢迎任何改进代码的建议。
这是一个较小的示例,可能是您开始的地方:
use std::collections::HashMap;
struct Letter;
struct Alphabet<'a>{
vowels: Vec<Letter>,
letters: HashMap<u8, &'a Letter>
}
impl<'a> Alphabet<'a> {
fn add(&mut self, l: Letter) {
self.vowels.push(l);
self.letters.insert(42, &self.vowels.last().unwrap());
}
}
fn main() {}
Run Code Online (Sandbox Code Playgroud)
然后您遵循编译器错误1:
use std::collections::HashMap;
struct Letter;
struct Alphabet<'a>{
vowels: Vec<Letter>,
letters: HashMap<u8, &'a Letter>
}
impl<'a> Alphabet<'a> {
fn add(&mut self, l: Letter) {
self.vowels.push(l);
self.letters.insert(42, &self.vowels.last().unwrap());
}
}
fn main() {}
Run Code Online (Sandbox Code Playgroud)
然后继续,直到你得到这样的东西:
use std::collections::HashMap;
struct Letter;
struct Alphabet<'a>{
vowels: Vec<Letter>,
letters: HashMap<u8, &'a Letter>
}
impl<'a> Alphabet<'a> {
fn new() -> Alphabet<'a> {
Alphabet { vowels: Vec::new(), letters: HashMap::new() }
}
fn add(&'a mut self, l: Letter) {
self.vowels.push(l);
self.letters.insert(42, &self.vowels.last().unwrap());
}
fn parse() -> Alphabet<'a> {
let mut a = Alphabet::new();
a.add(Letter);
a
}
}
fn main() {}
Run Code Online (Sandbox Code Playgroud)
根本问题是您不能引用自己的成员 2。在一般情况下,每当您移动结构时,所有成员变量的内存位置都会发生变化,从而使所有引用无效。这是一件坏事,Rust 会阻止你。
您收到的错误消息指出,没有可能的生命周期可以满足您的需求——引用仅在结构不移动时有效,但您想从方法返回结构,移动它。
“可是等等!” 你说,“我有一个Vec,里面的内容Vec在堆上,不会移动!”。虽然技术上是正确的(最好的那种),但 Rust 并没有在那个细粒度的级别上跟踪事物。
这里的一般解决方案是将您的结构分成两部分。Alphabet仅使用Vecs 将JSON 中的所有内容解析为结构体。然后将该结构(可能是通过引用,也可能是通过值)传递给一个AlphabetSoup结构。该结构可以HashMap一次创建所有内容并提供一个地方来缓存您的值。
1较新的编译器实际上删除了这个建议,因为误报率太高,它引入了更多的混乱而不是帮助。
2实际上,你可以有你自己的成员引用,但你永远不能移动的物体,这使得它不切实际的大多数情况下。
| 归档时间: |
|
| 查看次数: |
779 次 |
| 最近记录: |