工厂方法:实例寿命不够长

2023-12-04

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

Letter由单个字符和有关其与其他字母关系的规则组成。

Alphabet包含元音和辅音的向量以及引用这些向量中字母的哈希图。这样做是为了可以在 O(1) 时间内检索字母的规则。

我创建了一个工厂方法来从 json 字符串读取字母表(代码如下),但收到一条错误消息,指出字母表实例的生存时间不够长。

src/word_generator/alphabet.rs:47:6: 47:14 错误:alphabet才不是 活得足够长 src/word_generator/alphabet.rs:47 字母表.add_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)->字母表{

注意:...但借用的值仅对块后缀有效 以下语句 3 在 40:37 src/word_generator/alphabet.rs:40 让 mut 字母表 = 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());
            }
        }

    }
}

P.S.:我对 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() {}

You then followed the compiler error1:

<anon>:12:46: 12:52 error: cannot infer an appropriate lifetime for lifetime parameter 'a in function call due to conflicting requirements
<anon>:12         self.letters.insert(42, &self.vowels.last().unwrap());
                                                       ^~~~~~
<anon>:10:5: 13:6 help: consider using an explicit lifetime parameter as shown: fn add(&'a mut self, l: Letter)

继续,直到你得到这样的东西:

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() {}

The root problem is that you cannot have references to your own members 2. In the general case, whenever you moved the structure, then the memory location of all the member variables would change, invalidating all the references. This is a bad thing, and Rust would stop you.

您收到的错误消息指出,没有可能的生命周期可以满足您的需求 - 引用仅在结构不移动时有效,但您希望从方法返回结构,移动它.

“可是等等!”你说:“我有一个Vec和内容Vec在堆上并且不会移动!”。虽然从技术上来说是正确的(最好的正确方式),但 Rust 并没有在那么细粒度的级别上跟踪事物。

这里的一般解决方案是将您的结构分成两部分。将 JSON 中的所有内容解析为Alphabet结构体仅包含Vecs。然后将该结构(可能通过引用,也可能通过值)传递给AlphabetSoup结构。该结构可以创建HashMap一次全部完成并提供一个地方来缓存您的值。

1 Newer compilers actually removed this suggestion because the false-positive rate was too high and it introduced more confusion than it helped.

2 You actually can have references to your own members, but you can then never move the object, which makes it impractical for most cases.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

工厂方法:实例寿命不够长 的相关文章

随机推荐