我有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)
}
}
在不复制哈希表中的字符串的情况下编写查找函数的正确方法是什么?
答案 0 :(得分:14)
当您从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())
}
}