好的,您确实无法这样做。一般情况下,我可以提供两种主要方法,并针对您的示例进行解释。
拆分借用
这种方法可能是其他方法中最困难和/或最慢的方法。只需按照借用检查器的要求操作:不要混淆可变和不可变的借用。对于您的情况,可以简单地在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) {
for e in self.edges.borrow_mut().iter_mut() {
if e.0 == node {
std::mem::swap(&mut e.0, &mut e.1);
}
}
}
记住,
RefCell
不是
Sync
,因此它不能在线程之间共享。对于涉及到线程的情况,
Mutex
或
RwLock
是一种替代方案。
mutate_using_node
函数读取self
的哪些部分,并对其进行了什么样的变异? - Solomon Uckopartial_ref
crate,但我对它不太了解。 - Solomon Ucko