【发布时间】:2021-04-24 12:53:22
【问题描述】:
我有一个将其数据存储在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 中的东西的引用,所以即使我想返回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
}
}
可编译示例in the playground。
this one 等相关问题假定内部引用始终可用,因此它们不存在该问题。
我找到了Ref::filter_map() 和solve this,但它还没有在稳定版上可用,目前还不清楚它离稳定还有多远。除非有其他选择,否则我会接受使用 unsafe 的解决方案,前提是它是可靠的并且依赖于书面保证。
【问题讨论】: