首页 > 解决方案 > 在不违反借用规则的情况下,将相同的对象添加到 hashmap 和 vector

问题描述

在与所有权、寿命、移动和借用错误进行了长时间的斗争之后,我在add_turtle_ref. 期望的行为是add_turtle_ref将输入添加trefself.turtles, aVec<TurtleRef>self.map, a HashMap<&str, Vec<TurtleRef>>

游乐场

use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

#[derive(Clone)]
pub struct TurtleRef {
    t: Rc<RefCell<Turtle>>,
}
impl TurtleRef {
    pub fn new(r: Turtle) -> TurtleRef {
        TurtleRef {
            t: Rc::new(RefCell::new(r)),
        }
    }
}

pub struct Campus<'a> {
    turtles: Vec<TurtleRef>,
    map: HashMap<&'a str, Vec<TurtleRef>>,
}

impl Campus<'_> {
    pub fn new() -> Campus<'static> {
        Campus {
            turtles: Vec::new(),
            map: HashMap::new(),
        }
    }
    pub fn size(&self) -> usize {
        self.turtles.len()
    }
    pub fn add_turtle(&mut self, turtle: Turtle) {
        self.add_turtle_ref(TurtleRef::new(turtle));
    }

    pub fn add_turtle_ref(&mut self, tref: TurtleRef) {
        self.turtles.push(tref.clone());
        let n = tref.t.borrow().name();
        self.map.entry(n).or_insert(Vec::new()).push(tref.clone());
    }
    pub fn breed_turtles(&mut self, t1_index: usize, t2_index: usize, child_name: String) {
        let n = self.size();
        if t1_index > n - 1 || t2_index > n - 1 {
            panic!("out of bounds");
        }
        let tref = Turtle::breed(
            &mut self.turtles[t1_index].t.borrow_mut(),
            &mut self.turtles[t2_index].t.borrow_mut(),
            child_name,
        );
        self.add_turtle_ref(TurtleRef { t: tref });
    }
}

#[derive(Debug)]
pub struct Turtle {
    name: String,
    children: Vec<Rc<RefCell<Turtle>>>,
}

impl Turtle {
    pub fn new(name: String) -> Turtle {
        Turtle {
            name: name,
            children: Vec::new(),
        }
    }
    pub fn name(&self) -> &String {
        &self.name
    }
    pub fn add_child(&mut self, t: Rc<RefCell<Turtle>>) {
        self.children.push(t);
    }
    pub fn breed(t1: &mut Turtle, t2: &mut Turtle, name: String) -> Rc<RefCell<Turtle>> {
        let s = Rc::new(RefCell::new(Turtle {
            name: name,
            children: Vec::new(),
        }));
        t1.add_child(Rc::clone(&s));
        t2.add_child(Rc::clone(&s));
        s
    }
}

错误:

error[E0597]: `tref.t` does not live long enough
  --> src/lib.rs:38:17
   |
36 |     pub fn add_turtle_ref(&mut self, tref: TurtleRef) {
   |                           --------- has type `&mut Campus<'1>`
37 |         self.turtles.push(tref.clone());
38 |         let n = tref.t.borrow().name();
   |                 ^^^^^^ borrowed value does not live long enough
39 |         self.map.entry(n).or_insert(Vec::new()).push(tref.clone());
   |         ----------------- argument requires that `tref.t` is borrowed for `'1`
40 |     }
   |     - `tref.t` dropped here while still borrowed

error[E0716]: temporary value dropped while borrowed
  --> src/lib.rs:38:17
   |
36 |     pub fn add_turtle_ref(&mut self, tref: TurtleRef) {
   |                           --------- has type `&mut Campus<'1>`
37 |         self.turtles.push(tref.clone());
38 |         let n = tref.t.borrow().name();
   |                 ^^^^^^^^^^^^^^^       - temporary value is freed at the end of this statement
   |                 |
   |                 creates a temporary which is freed while still in use
39 |         self.map.entry(n).or_insert(Vec::new()).push(tref.clone());
   |         ----------------- argument requires that borrow lasts for `'1`

我尝试了各种巧妙的技巧,例如获取名称,将其取消引用为普通字符串,然后将其String转回 a &String,但这只会导致 Rust 编译器更快地抱怨:你不能取消引用字符串!

标签: rustborrow-checkerownership

解决方案


推荐阅读