Rust 中的"cannot return value referencing temporary value"和内部可变性



我在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) -> &regex::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所拥有的,所以在内部使用它应该是可以的(因为函数不是pub)。

我还尝试了以下操作(但它失败了,并显示了相同的消息)

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.unwrap().regexp)
}

我该怎么解决?

您可以通过使用.as_ref()&Option<_>转换为Option<&_>来修复Ref::map版本,以便打开包装作为参考:

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) -> &regex::Regex {
&self.regexp_data.get_or_init(|| self.compile_regexp()).regexp
}
}

您可以简单地使用get_or_init来获得相同的效果。CCD_ 15和CCD_。

在操场上看。

最新更新