如何返回可选结构体字段内的值的引用?

5

我正在尝试改进在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方法的结构中,是否有可能以任何方式返回对这些数据的引用?如果不是这种方式,那么我该怎么做才能获得拥有计算数据并在需要时返回引用的Cacher的功能?


2
看起来Option::get_or_insert_with会有所帮助。 - kmdreko
2个回答

2
你已经接近正确答案了。你只需要返回指向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()
    }
}

Playground


1

一种更简单且略微更有效的替代方法是使用get_or_insert_with:

fn value(&mut self, arg: &U) -> &U {
    let calculation = &self.calculation;
    self.value.get_or_insert_with(|| calculation(arg))
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接