我如何 return 对可选结构字段内值的引用?
How do I return a reference to the value inside an optional struct field?
我正在尝试改进 The Rust Programming Language 中描述的 Cacher
类型。其中一项改进建议指出 Cacher
应该可用于多种类型。为此,我编写了以下代码:
struct Cacher<T, U>
where
T: Fn(&U) -> U,
{
calculation: T,
value: Option<U>,
}
impl<T, U> Cacher<T, U>
where
T: Fn(&U) -> U,
{
fn new(calculation: T) -> Cacher<T, U> {
Cacher {
calculation,
value: None,
}
}
fn value(&mut self, arg: &U) -> &U {
match self.value {
Some(v) => &v,
None => {
let v = (self.calculation)(arg);
self.value = Some(v);
&v
}
}
}
}
编译器抱怨:
error[E0507]: cannot move out of `self.value.0` which is behind a mutable reference
--> src/lib.rs:21:15
|
21 | match self.value {
| ^^^^^^^^^^ help: consider borrowing here: `&self.value`
22 | Some(v) => &v,
| -
| |
| data moved here
| move occurs because `v` has type `U`, which does not implement the `Copy` trait
error[E0515]: cannot return reference to local variable `v`
--> src/lib.rs:22:24
|
22 | Some(v) => &v,
| ^^ returns a reference to data owned by the current function
error[E0515]: cannot return reference to local variable `v`
--> src/lib.rs:26:17
|
26 | &v
| ^^ returns a reference to data owned by the current function
error[E0382]: borrow of moved value: `v`
--> src/lib.rs:26:17
|
24 | let v = (self.calculation)(arg);
| - move occurs because `v` has type `U`, which does not implement the `Copy` trait
25 | self.value = Some(v);
| - value moved here
26 | &v
| ^^ value borrowed here after move
我想这是因为 v
是函数的局部变量。但是,鉴于实际数据存在于 value
方法之外的结构中,是否不可能以任何方式 return 引用此数据?如果不是这样,那么我需要做些什么才能获得拥有计算数据的 Cacher
的功能,并在需要时 returns 引用?
你差不多明白了。你只需要 return 对象的引用 inside Option
:
struct Cacher<T, U>
where
T: Fn(&U) -> U
{
calculation: T,
value: Option<U>,
}
impl<T, U> Cacher<T, U>
where
T: Fn(&U) -> U
{
fn new(calculation: T) -> Cacher<T, U> {
Cacher {
calculation,
value: None,
}
}
fn value(&mut self, arg: &U) -> &U {
if self.value.is_none() {
let v = (self.calculation)(arg);
self.value = Some(v);
}
self.value.as_ref().unwrap()
}
}
一个更简单且稍微更有效的替代方法是使用 get_or_insert_with
:
fn value(&mut self, arg: &U) -> &U {
let calculation = &self.calculation;
self.value.get_or_insert_with(|| calculation(arg))
}
我正在尝试改进 The Rust Programming Language 中描述的 Cacher
类型。其中一项改进建议指出 Cacher
应该可用于多种类型。为此,我编写了以下代码:
struct Cacher<T, U>
where
T: Fn(&U) -> U,
{
calculation: T,
value: Option<U>,
}
impl<T, U> Cacher<T, U>
where
T: Fn(&U) -> U,
{
fn new(calculation: T) -> Cacher<T, U> {
Cacher {
calculation,
value: None,
}
}
fn value(&mut self, arg: &U) -> &U {
match self.value {
Some(v) => &v,
None => {
let v = (self.calculation)(arg);
self.value = Some(v);
&v
}
}
}
}
编译器抱怨:
error[E0507]: cannot move out of `self.value.0` which is behind a mutable reference
--> src/lib.rs:21:15
|
21 | match self.value {
| ^^^^^^^^^^ help: consider borrowing here: `&self.value`
22 | Some(v) => &v,
| -
| |
| data moved here
| move occurs because `v` has type `U`, which does not implement the `Copy` trait
error[E0515]: cannot return reference to local variable `v`
--> src/lib.rs:22:24
|
22 | Some(v) => &v,
| ^^ returns a reference to data owned by the current function
error[E0515]: cannot return reference to local variable `v`
--> src/lib.rs:26:17
|
26 | &v
| ^^ returns a reference to data owned by the current function
error[E0382]: borrow of moved value: `v`
--> src/lib.rs:26:17
|
24 | let v = (self.calculation)(arg);
| - move occurs because `v` has type `U`, which does not implement the `Copy` trait
25 | self.value = Some(v);
| - value moved here
26 | &v
| ^^ value borrowed here after move
我想这是因为 v
是函数的局部变量。但是,鉴于实际数据存在于 value
方法之外的结构中,是否不可能以任何方式 return 引用此数据?如果不是这样,那么我需要做些什么才能获得拥有计算数据的 Cacher
的功能,并在需要时 returns 引用?
你差不多明白了。你只需要 return 对象的引用 inside Option
:
struct Cacher<T, U>
where
T: Fn(&U) -> U
{
calculation: T,
value: Option<U>,
}
impl<T, U> Cacher<T, U>
where
T: Fn(&U) -> U
{
fn new(calculation: T) -> Cacher<T, U> {
Cacher {
calculation,
value: None,
}
}
fn value(&mut self, arg: &U) -> &U {
if self.value.is_none() {
let v = (self.calculation)(arg);
self.value = Some(v);
}
self.value.as_ref().unwrap()
}
}
一个更简单且稍微更有效的替代方法是使用 get_or_insert_with
:
fn value(&mut self, arg: &U) -> &U {
let calculation = &self.calculation;
self.value.get_or_insert_with(|| calculation(arg))
}