我有一种将其数据存储在 a 后面的容器中的类型,该容器Rc<RefCell<>>
大部分对公共 API 隐藏。例如:
struct Value;
struct Container {
storage: Rc<RefCell<HashMap<u32, Value>>>,
}
impl Container {
fn insert(&mut self, key: u32, value: Value) {
self.storage.borrow_mut().insert(key, value);
}
fn remove(&mut self, key: u32) -> Option<Value> {
self.storage.borrow_mut().remove(&key)
}
// ...
}
但是,查看容器内部需要返回一个Ref
. 这可以使用Ref::map()
- 例如:
// peek value under key, panicking if not present
fn peek_assert(&self, key: u32) -> Ref<'_, Value> {
Ref::map(self.storage.borrow(), |storage| storage.get(&key).unwrap())
}
但是,我想要一个不惊慌失措的peek
, 会返回Option<Ref<'_, Value>>
. 这是一个问题,因为Ref::map
要求您返回对 内部存在的东西的引用RefCell
,所以即使我想 return Ref<'_, Option<Value>>
,它也不起作用,因为返回的选项storage.get()
是短暂的。
尝试使用从以前查找的密钥Ref::map
创建一个Ref
也不会编译:
// doesn't compile apparently the borrow checker doesn't understand that `v`
// won't outlive `_storage`.
fn peek(&self, key: u32) -> Option<Ref<'_, Value>> {
let storage = self.storage.borrow();
if let Some(v) = storage.get(&key) {
Some(Ref::map(storage, |_storage| v))
} else {
None
}
}
有效的方法是执行两次查找,但这是我真正想避免的事情:
// works, but does lookup 2x
fn peek(&self, key: u32) -> Option<Ref<'_, Value>> {
if self.storage.borrow().get(&key).is_some() {
Some(Ref::map(self.storage.borrow(), |storage| {
storage.get(&key).unwrap()
}))
} else {
None
}
}
操场上的可编译示例。
像这样的相关问题假设内部参考总是可用的,所以他们没有这个问题。
我发现Ref::filter_map()
哪个可以解决这个问题,但它还没有稳定版,而且还不清楚它离稳定还有多远。除非有其他选择,否则我会接受一个使用的解决方案,unsafe
只要它是健全的并且依赖于书面保证。