16

我有一个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!"));
}

操场

如果我删除RefCell然后一切正常:

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

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

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

4

1 回答 1

17

当您从 a 借用时RefCell,您获得的引用的生命周期比RefCell's 短。这是因为引用的生命周期受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())
    }
}
于 2015-05-17T00:29:38.180 回答