我如何告诉编译器在不删除整个结构的情况下释放结构中的借用?

How can I tell the compiler to release a borrow in a struct without dropping the entire struct?

我有以下代表数字计算计划的结构:

pub struct NfftPlan<'a> {
    x: Option<&'a [f64]>,
    f_hat: Option<&'a [Complex64]>,
    // ...
}

它有一个set_f_hat方法:

pub fn set_f_hat(&mut self, f_hat: &'a [Complex64]) {
    self.f_hat = Some(f_hat);
}

和一个execute方法:

pub fn execute(&self) -> Vec<Complex64>

不变地使用 f_hat

我想按以下方式使用它:

let mut f_hat = vec![1,2,3,4];
let plan = NfftPlan::new()
plan.set_f_hat(&f_hat);
plan.execute();
f_hat[0] = 3; // Change f_hat to a new value
plan.execute(); //New computation

这失败了,因为我无法在 plan 仍然存在的情况下改变 f_hat。 有没有办法让 plan 释放对 f_hat 的借用,这样我就可以改变 f_hat 向量? 像这样:

releasedata(&self) {
    self.f_hat = None
} //Now the compiler forgets that plan would hold an borrow to f_hat

我知道 Rust 不允许我在存在借用向量时更改向量,在本例中是通过 NfftPlan 结构中的 f_hat 引用。 我想要一种方法告诉编译器在 NfftPlan 结构中删除对向量的引用而不删除整个结构。

说明

How can I tell the compiler to release a borrow

你不能,句号。这不是你 "tell" 编译器的事情,编译器什么都知道。你只能完全停止使用参考。

without dropping the entire struct

删除不会清除借用,只有不再使用的借用才会清除,这可能会在删除时发生。

f_hat[0] = 3; // Change f_hat to a new value
plan.execute(); //New computation

正是 Rust 试图阻止的代码类型之一。 plan.execute() 应该 return 一个不同的值一点也不明显,因为一些明显无关的值已经改变。

解决方案

在类型系统中对其进行编码

我会构建我的类型以反映它们需要如何使用,创建一次性值,这些值只有在所有内容组合在一起后才能执行。这意味着借用 f_mut 的结构一完成就被丢弃;请注意这是如何完全删除 Option 的:

fn main() {
    let mut f_hat = 42;

    let plan = Plan::default();
    plan.set_f_hat(&f_hat).execute();

    f_hat = 3;
    plan.set_f_hat(&f_hat).execute();
}

#[derive(Debug, Default)]
struct Plan<'a> {
    x: Option<&'a i32>,
}

impl<'a> Plan<'a> {
    fn set_f_hat(&self, f_hat: &'a i32) -> PlanPlus<'a> {
        PlanPlus { x: self.x, f_hat }
    }
}

#[derive(Debug)]
struct PlanPlus<'a> {
    x: Option<&'a i32>,
    f_hat: &'a i32,
}

impl<'a> PlanPlus<'a> {
    fn execute(&self) {}
}

使用内部可变性和引用计数

use std::{cell::Cell, rc::Rc};

#[derive(Debug, Default)]
struct Plan<'a> {
    x: Option<&'a i32>,
    f_hat: Option<Rc<Cell<i32>>>,
}

impl<'a> Plan<'a> {
    fn set_f_hat(&mut self, f_hat: Rc<Cell<i32>>) {
        self.f_hat = Some(f_hat);
    }
    fn execute(&self) {}
}

fn main() {
    let f_hat = Rc::new(Cell::new(42));

    let mut plan = Plan::default();
    plan.set_f_hat(f_hat.clone());
    plan.execute();

    f_hat.set(3);
    plan.execute();
}

识别成员是可变的

#[derive(Debug, Default)]
struct Plan<'a> {
    x: Option<&'a i32>,
    f_hat: Option<&'a mut i32>,
}

impl<'a> Plan<'a> {
    fn f_hat(&mut self) -> &mut Option<&'a mut i32> {
        &mut self.f_hat
    }

    fn execute(&self) {}
}

fn main() {
    let mut f_hat = 42;

    let mut plan = Plan::default();
    *plan.f_hat() = Some(&mut f_hat);
    plan.execute();
    **plan.f_hat().as_mut().unwrap() = 3;
    plan.execute();
}

另请参阅:

  • Moved variable still borrowing after calling `drop`?