问题描述
我在 Rust 中有以下代码:
pub struct RegExpFilter {
...
regexp_data: RefCell<Option<RegexpData>>,...
}
struct RegexpData {
regexp: regex::Regex,string: String
}
...
pub fn is_regexp_compiled(&self) -> bool {
self.regexp_data.borrow().is_some()
}
pub fn compile_regexp(&self) -> RegexpData {
...
}
fn regexp(&self) -> ®ex::Regex {
if !self.is_regexp_compiled() { // lazy computation that mutates the struct
self.regexp_data.replace(Some(self.compile_regexp()));
}
&self.regexp_data.borrow().as_ref().unwrap().regexp
}
pub fn matches(&self,location: &str) -> bool {
self.regexp().find(location)
}
regexp 是惰性计算的,捕获 &mut self
我不需要所以使用 RefCell
。
我收到以下消息:
&self.regexp_data.borrow().as_ref().unwrap().regexp
| ^-------------------------^^^^^^^^^^^^^^^^^^^^^^^^^
| ||
| |temporary value created here
| returns a value referencing data owned by the current function
编译器消息似乎很明确:Ref
是由 borrow()
临时创建并返回到外部。但是我相信 Option
(self.regexp_data
) 由 RefCell
拥有,它由结构本身拥有,所以在内部使用它应该没问题(因为函数不是 {{1} }).
我也尝试了以下操作(但失败并显示相同的消息)
pub
我该如何解决?
解决方法
您可以通过使用 Ref::map
将 .as_ref()
转换为 &Option<_>
以作为参考解包来修复 Option<&_>
版本:
fn regexp(&self) -> impl Deref<Target = regex::Regex> + '_ {
if !self.is_regexp_compiled() {
self.regexp_data.replace(Some(self.compile_regexp()));
}
Ref::map(self.regexp_data.borrow(),|it| &it.as_ref().unwrap().regexp)
// ^^^^^^^^
}
在这种情况下,我提倡使用 once_cell 板条箱中的 OnceCell
:
use once_cell::sync::OnceCell;
pub struct RegexpData {
regexp: regex::Regex,string: String,}
pub struct RegExpFilter {
regexp_data: OnceCell<RegexpData>,}
impl RegExpFilter {
pub fn compile_regexp(&self) -> RegexpData {
unimplemented!()
}
fn regexp(&self) -> ®ex::Regex {
&self.regexp_data.get_or_init(|| self.compile_regexp()).regexp
}
}
您可以简单地使用 get_or_init
来获得相同的效果。 OnceCell
和 Lazy
(在同一个 crate 中)对于惰性求值非常方便。
在 playground 上查看。