This question already has answers here:
How do I return a reference to something inside a RefCell without breaking encapsulation?
(3个答案)
去年关门了。
我有一个RefCell<HashMap>要借用表,找到一个键,并返回对结果的引用:
use std::cell::RefCell;
use std::collections::HashMap;

struct Frame {
    map: RefCell<HashMap<String, String>>,
}

impl Frame {
    fn new() -> Frame {
        Frame {
            map: RefCell::new(HashMap::new()),
        }
    }

    fn lookup<'a>(&'a self, k: &String) -> Option<&'a String> {
        self.map.borrow().get(k)
    }
}

fn main() {
    let f = Frame::new();
    println!("{}", f.lookup(&"hello".to_string()).expect("blargh!"));
}

playground
如果删除RefCell,则一切正常:
struct Frame {
    map: HashMap<String, String>,
}

impl Frame {
    fn lookup<'a>(&'a self, k: &String) -> Option<&'a String> {
        self.map.get(k)
    }
}

在不复制哈希表中的字符串的情况下编写查找函数的正确方法是什么?

最佳答案

当您从RefCell借用时,您得到的引用的生存期比RefCell短,这是因为引用的生存期受到borrow()返回的保护的限制。该保护确保在删除该保护之前,其他任何人都不能对该值进行可变引用。
但是,您试图返回一个值而不让卫兵活着。如果Frame有一个带&self参数的方法,但试图对映射进行变异(这在RefCell中是可能的——如果不需要这样做,那么放弃RefCell并在对映射进行变异的方法上编写&mut self),则可能会意外地破坏其他人引用的String。这正是借阅检查器设计用来报告的错误!
如果映射值实际上是不可变的(即您的类型不允许对映射值进行变异),您还可以将它们包装在映射中的Rc中。因此,您可以返回Rc<String>的克隆(这只克隆引用计数指针,而不是底层字符串),这将允许您在从函数返回之前释放映射上的借用。

struct Frame {
    map: RefCell<HashMap<String, Rc<String>>>
}

impl Frame {
    fn lookup(&self, k: &String) -> Option<Rc<String>> {
        self.map.borrow().get(k).map(|x| x.clone())
    }
}

10-02 02:16