工厂方法:实例存活时间不够长

W.K*_*K.S 3 rust

我正在用 Rust 开发一个单词生成器。该应用程序由两个主要结构组成:LetterAlphabet.

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 很陌生,因此非常欢迎任何改进代码的建议。

She*_*ter 7

这是一个较小的示例,可能是您开始的地方:

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 次

最近记录:

7 年,6 月 前