How do I borrow a RefCell<HashMap>, find a key, and return a reference to the result? [duplicate]

我的未来我决定 提交于 2019-11-26 04:55:05

问题


This question already has an answer here:

  • How do I return a reference to something inside a RefCell without breaking encapsulation? 3 answers

I have a RefCell<HashMap> and want to borrow the table, find a key, and return a reference to the result:

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)

If I remove the RefCell then everything works okay:

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

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

What is the correct way to write the lookup function without copying the string in the hashtable?


回答1:


When you borrow from a RefCell, the reference you get has a shorter lifetime than the RefCell's. That's because the reference's lifetime is restricted by the guard returned by borrow(). That guard ensures that nobody else can take a mutable reference to the value until the guard is dropped.

However, you are trying to return a value without keeping a guard alive. If Frame had a method that took a &self argument but tried to mutate the map (which is possible with RefCell — if you don't need to do that, then ditch the RefCell and write &mut self on the methods that mutate the map), you could accidentally destroy a String that somebody else has a reference to. That is exactly the kind of errors that the borrow checker was designed to report!

If the map values are effectively immutable (i.e. your type will not allow mutating the map's values), you could also wrap them in an Rc in your map. You could therefore return a clone of the Rc<String> (this only clones the reference-counted pointer, not the underlying string), which would let you release the borrow on the map before returning from the function.

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())
    }
}


来源:https://stackoverflow.com/questions/30281664/how-do-i-borrow-a-refcellhashmap-find-a-key-and-return-a-reference-to-the-re

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!