Rust,在迭代中需要一个可变的 Self 引用

标签 rust borrow-checker

我在 Rust 中有一个 Graph 数据结构:

type NodeIndex = usize;

struct Graph {
    nodes: Vec<NodeIndex>,
    edges: Vec<(NodeIndex, NodeIndex)>,
}
我想遍历函数内的所有节点并调用一个函数,该函数使用每个节点作为元素来改变图形,例如:
impl Graph {
    fn mutate_fn(&mut self) {
        for node in self.nodes {
            self.mutate_using_node(node);
        }
    }

    fn mutate_using_node(&mut self, node: NodeIndex) {
        // mutate self here
    }
}
这是行不通的,因为我会有不止一个可变引用。我也不能通过 &self,因为那样我就会有一个可变引用和一个不可变引用。这在 Rust 中是如何处理的?

最佳答案

嗯,你确实不能这样做。我可以列举两种普遍适用的主要方法,特别是你的例子
拆分借款
这种方式可能是最难和/或最慢的方式。只做借用检查器想要的:不要混淆可变和不可变借用。对于您的情况,可以像克隆 mutate_fn 中的节点一样简单:

let nodes = self.nodes.clone();
for node in nodes {
    self.mutate_using_node(node);
}
没有太多细节很难推理,但我认为这是该方法的唯一方法。如果你只是改变边缘,例如这样:
fn mutate_using_node(&mut self, node: NodeIndex) {
    for e in &mut self.edges {
        if e.0 == node {
            std::mem::swap(&mut e.0, &mut e.1);
        }
    }
}
你可以简单地通过联合这些功能来处理它:
for node in self.nodes.iter().copied() {
    for e in &mut self.edges {
        if e.0 == node {
            std::mem::swap(&mut e.0, &mut e.1);
        }
    }
}
因此,总的来说,没有用于拆分代码的最终分步指南(可能复制除外)。它确实取决于代码语义。
内部可变性
RefCell 是关于。它基本上在运行时处理借用检查规则,如果这些规则被破坏,你会感到 panic 。对于看起来像这样的情况:
use std::cell::RefCell;

type NodeIndex = usize;

struct Graph {
    nodes: RefCell<Vec<NodeIndex>>,
    edges: RefCell<Vec<(NodeIndex, NodeIndex)>>,
}

fn mutate_fn(&self) {
    for &node in self.nodes.borrow().iter() {
        self.mutate_using_node(node);
    }
}

fn mutate_using_node(&self, node: NodeIndex) { // <- notice immutable ref
    for e in self.edges.borrow_mut().iter_mut() {
        if e.0 == node {
            std::mem::swap(&mut e.0, &mut e.1);
        }
    }
}
请记住,RefCell不是 Sync ,因此它不能在线程之间共享。适用于带线程的 shell Mutex RwLock 是一个替代方案。

关于Rust,在迭代中需要一个可变的 Self 引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62915484/

相关文章:

reference - 如何制作引用文献的副本? (生活问题)

rust - 如何使 `unwrap_or` 返回一个由零组成的向量?

rust - 将可变自引用传递给拥有对象的方法

rust - 如何使用滑动窗口对生成迭代器?

rust - 如何为我的 rust 结构实现 trait FromPyObject

rust - 为什么这是错误的 "unable to infer enough type information about ` _`"

rust - 如何从流中读取特定数量的字节?

rust - 如何实现具有具体生命周期的 FromStr?

rust - 将包含引用的结构移动到静态闭包中不起作用

javascript - 难以在 JavaScript 中实现简化的借用检查器