“不能返回引用临时值的值”和 Rust 中的内部可变性
Posted
技术标签:
【中文标题】“不能返回引用临时值的值”和 Rust 中的内部可变性【英文标题】:"cannot return value referencing temporary value" and interior mutability in Rust 【发布时间】:2021-05-19 04:28:15 【问题描述】:我在 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)
正则表达式是惰性计算的,捕获&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)
我该如何解决?
【问题讨论】:
如果不保留Ref<T>
,就无法从RefCell<T>
获得&T
,RefCell
如何知道何时允许borrow()
和borrow_mut()
。见this Q&A。
【参考方案1】:
您可以通过使用.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)
// ^^^^^^^^
在这种情况下,我提倡使用 OnceCell
来自 once_cell 板条箱:
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 上查看。
【讨论】:
以上是关于“不能返回引用临时值的值”和 Rust 中的内部可变性的主要内容,如果未能解决你的问题,请参考以下文章
Rust-线程:使用Sync和Send trait的可扩展并发
Rust-线程:使用Sync和Send trait的可扩展并发