我怎样才能在Rust中创建引用其他对象的对象?

n3ipq98p  于 2023-03-02  发布在  其他
关注(0)|答案(1)|浏览(117)

我刚学会生 rust ,我想要的是:

  • 一组属性(Prop)
  • 一组类别(Cat),由一个或多个 prop 定义
  • 字典(字典),存储这些内容。一旦创建,猫和 prop 是只读的。

这看起来很简单,但是Rust让它变得非常困难;以我的编程背景,这是违反直觉和令人沮丧的,我不能想出正确的方法来做。

use std::collections::HashMap;

struct Prop<'a> {
    name: &'a str
}

type PropVec<'a> = Vec<&'a Prop<'a>>;

struct Cat<'a> {
    name: &'a str,
    props: PropVec<'a>
}

struct Dict<'a> {
    props: HashMap<&'a str, Prop<'a>>,
    cats:  HashMap<&'a str, Cat<'a>>,
}

impl<'a> Dict<'a> {
    pub fn define_prop(&mut self, name: &'a str) {
        self.props.insert(name, Prop { name });
    }

    pub fn prop(&self, name: &str) -> Option<&Prop> {
        self.props.get(name)
    }

    pub fn define_cat(&mut self, name: &'a str, prop_names: Vec<&'a str>) {
        let mut props: PropVec<'a> =  Vec::new();

        for name in prop_names {
            if let Some(prop) = self.prop(name) {
                props.push(prop);
            }
        }
        
        self.cats.insert(name, Cat { name: name, props });
    }
}

fn main() {
    let mut d = Dict { props: HashMap::new(), cats: HashMap::new() };
    d.define_prop("foo");
    d.define_cat("bar", vec!("foo"));
}

编译器说:

error: lifetime may not live long enough
  --> src/main.rs:29:24
   |
19 | impl<'a> Dict<'a> {
   |      -- lifetime `'a` defined here
...
28 |     pub fn define_cat(&mut self, name: &'a str, prop_names: Vec<&'a str>) {
   |                       - let's call the lifetime of this reference `'1`
29 |         let mut props: PropVec<'a> =  Vec::new();
   |                        ^^^^^^^^^^^ type annotation requires that `'1` must outlive `'a`

error[E0502]: cannot borrow `self.cats` as mutable because it is also borrowed as immutable
  --> src/main.rs:37:9
   |
19 | impl<'a> Dict<'a> {
   |      -- lifetime `'a` defined here
...
29 |         let mut props: PropVec<'a> =  Vec::new();
   |                        ----------- type annotation requires that `*self` is borrowed for `'a`
...
32 |             if let Some(prop) = self.prop(name) {
   |                                 --------------- immutable borrow occurs here
...
37 |         self.cats.insert(name, Cat { name: name, props });
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here

因此:
1.因为我使用的是引用,所以我需要把生存期放在任何地方,这导致了第一个错误。有没有其他的方法可以做到这一点?我试着用Box和Rc来代替,但是没有成功。如果没有,指定生存期的正确方法是什么?
1.第29行中关于 * self的注解有什么值得担心的吗?
1.我知道第一次借用self会阻止第二次借用,但肯定有可能得到Prop,或者对它的引用,并将其存储在其他地方?

rkue9o1l

rkue9o1l1#

type PropVecVec<&Prop>,并且包含对存储在Dict中的props的引用:

use std::collections::HashMap;

struct Prop {
    name: String,
}

type PropVec<'a> = Vec<&'a Prop>;

struct Cat<'a> {
    name: String,
    props: PropVec<'a>,
}

struct Dict<'a> {
    props: HashMap<String, Prop>,
    cats: HashMap<String, Cat<'a>>,
}

impl<'a> Dict<'a> {
    pub fn define_prop(dict: &mut Dict, name: &str) {
        dict.props.insert(
            name.to_string(),
            Prop {
                name: name.to_string(),
            },
        );
    }

    pub fn define_cat(dict: &'a mut Dict<'a>, name: &str, prop_names: Vec<String>) {
        let mut props: PropVec = Vec::new();
        for name in prop_names {
            if let Some(prop) = dict.props.get(&name) {
                props.push(prop);
            }
        }
        dict.cats.insert(
            name.to_string(),
            Cat {
                name: name.to_string(),
                props,
            },
        );
    }
}

fn main() {
    let mut d = Dict {
        props: HashMap::new(),
        cats: HashMap::new(),
    };
    Dict::define_prop(&mut d, "foo");
    Dict::define_cat(&mut d, "bar", vec!["foo".to_string()]);
}

Playground

相关问题