【问题标题】:Rust, need a mutable reference of Self inside iterationRust,在迭代中需要一个可变的 Self 引用
【发布时间】:2020-11-04 23:42:56
【问题描述】:

我在 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 中是如何处理的?

【问题讨论】:

标签: rust borrow-checker


【解决方案1】:

嗯,你确实不能这样做。我可以列举两种普遍适用的主要方法,尤其是对您而言

拆分借款

这种方式可能是其他方式中最难和/或最慢的方式。做借用检查器想要的:不要混淆可变借用和不可变借用。对于您的情况,可以像克隆 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 差不多。它基本上在运行时处理借用检查规则,如果这些规则被破坏,你会感到恐慌。对于看起来像这样的情况:

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,因此它不能在线程之间共享。对于线程MutexRwLock 的情况是一种替代方案。

【讨论】:

  • 嗯,你也可以使用不安全的代码来解决这个问题。但你可能不想这样做。
  • 感谢您的回答。然而,编译器抱怨 borrow_mut() 不适用于 Vec.
  • 糟糕,错过了Graph 定义,已添加。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-16
  • 1970-01-01
  • 2021-11-08
  • 1970-01-01
相关资源
最近更新 更多