[英]“cannot return value referencing temporary value” and interior mutability in Rust
I have the following code in Rust:我在 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 is calculated lazily, capturing &mut self
i undesired so RefCell
is used.正则表达式是惰性计算的,捕获&mut self
i 不想要的,因此使用RefCell
。
I'm getting the following message:我收到以下消息:
&self.regexp_data.borrow().as_ref().unwrap().regexp
| ^-------------------------^^^^^^^^^^^^^^^^^^^^^^^^^
| ||
| |temporary value created here
| returns a value referencing data owned by the current function
The compiler message seems to be clear: Ref
is temporarily created by borrow()
and returned outside.编译器的信息似乎很清楚: Ref
是由borrow()
临时创建并返回到外部的。 However i believe Option
( self.regexp_data
) is owned by RefCell
which is owned by the struct itself, so it should be fine to use it internally (since the function is not pub
).但是我相信Option
( self.regexp_data
)归结构本身所有的RefCell
所有,所以在内部使用它应该没问题(因为 function 不是pub
)。
I've also tried the following (and it fails with the same message)我还尝试了以下方法(但失败并显示相同的消息)
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)
}
How can i solve it?我该如何解决?
You can fix the Ref::map
version by using .as_ref()
to convert the &Option<_>
to a Option<&_>
in order to to unwrap as a reference:您可以修复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)
// ^^^^^^^^
}
In this scenario, I'd advocate for using OnceCell
from the once_cell crate:在这种情况下,我提倡使用OnceCell
板条箱中的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
}
}
You can simply use get_or_init
to get the same effect.您可以简单地使用get_or_init
来获得相同的效果。 OnceCell
and Lazy
(in the same crate) are very convenient for lazy-evaluation. OnceCell
和Lazy
(在同一个 crate 中)对于惰性求值非常方便。
See it on the playground .在操场上看到它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.