Rust 中调用字段的函数并传递 &self

Mik*_*nko 6 ownership rust borrow-checker

我有一个MainStruct拥有 的实例HelperStruct。我想创建一个调用helper's 方法的方法。但helpers 方法确实需要(不可变)访问MainStruct

struct MainStruct {
    helper: HelperStruct,
}

impl MainStruct {
    pub fn call_helper(&mut self, args) { 
        // &mut self because the_method changes inner state of HelperStruct
        self.helper.the_method(self, args)
    }
}

impl HelperStruct {
    pub fn the_method(&mut self, owner: &MainStruct, args) {
        owner.other_method();
    }
}
Run Code Online (Sandbox Code Playgroud)

通过这个设置,我得到

error[E0502]: cannot borrow `self.helper` as mutable because it is also borrowed as immutable
214 |         self.helper.the_method(self, args)
    |         ^^^^^^^^^^^^----------^----^^^^^^^^^^^^^^^^^^^^^^
    |         |           |            |
    |         |           |            immutable borrow occurs here
    |         |           immutable borrow later used by call
    |         mutable borrow occurs here
Run Code Online (Sandbox Code Playgroud)

至关重要的是,它MainStruct仍然是与功能交互的主要接口(因此拥有 Helper 自己的 Main 不是一个选项)。

我应该如何重构我的代码(或者可能使用智能指针?),以便我可以从 Helper 内部与所有者进行交互?另外,保证the_method()只会在 的实例内调用MainStruct

实际背景:

MainStructField我的游戏。是HelperStruct负责路径的类,主要是 A*。A* 有许多存储其状态的大型数组。A* 通过后,只有其中一些需要重新初始化(或以其他方式清理)。

我最终多次调用 A*,因此我想避免每次传递时都完全重新初始化它。所以我将其存储在 中Field,并且仅reset()在通过后调用。

为了正确规划路径,A* 需要查看Field(障碍物等)。当 A* 正在运行时,它当然会改变它自己的一些领域,所以the_method,实际上

error[E0502]: cannot borrow `self.helper` as mutable because it is also borrowed as immutable
214 |         self.helper.the_method(self, args)
    |         ^^^^^^^^^^^^----------^----^^^^^^^^^^^^^^^^^^^^^^
    |         |           |            |
    |         |           |            immutable borrow occurs here
    |         |           immutable borrow later used by call
    |         mutable borrow occurs here
Run Code Online (Sandbox Code Playgroud)

需要有一个&mut self

Sil*_*olo 0

你需要让 Rust 相信,无论用HelperStruct做什么MainStruct,它都不会尝试通过访问自身,因为这构成了对你也 MainStruct可变引用的东西的不可变引用。

根据 的复杂性和需求HelperStruct,一种选择是将swap虚拟HelperStruct值放入其中MainStruct,然后调用(现已隔离的)上的函数HelperStruct

use std::mem::swap;

struct MainStruct {
    helper: HelperStruct,
}

impl MainStruct {
    pub fn call_helper(&mut self, args) { 
        let mut helper_struct = HelperStruct::default(); // Some dummy value
        swap(&mut helper_struct, &mut self.helper);
        helper_struct.the_method(self, args);
        swap(&mut helper_struct, &mut self.helper);
    }
}
Run Code Online (Sandbox Code Playgroud)

这样,就可以对除自身之外的HelperStruct.the_method所有内容进行不可变的访问,该访问已被暂时排除。完成后,我们将值交换回来,这不会造成任何损害。MainStruct