自我的多个部分怎么能在这里借用?这里的 self borrowed mutably 和 immutably 不是一样的吗?
How can multiple parts of self be borrowed here? Isn't self borrowed mutably as well as immutably here?
我有这个结构:
struct PhysicsState {
nodes: Vec<Node>,
edges: Vec<Edge>,
}
我正在尝试理解为什么这段代码可以编译:
impl PhysicsState {
fn remove_edge(&mut self, edge_index: usize) {
let edge = &self.edges[edge_index]; // first borrow here
// update the edge-index collection of the nodes connected by this edge
for i in 0..2 {
let node_index = edge.node_indices[i];
self.nodes[node_index].remove_edge(edge_index); // second (mutable) borrow here ?
}
}
}
虽然失败了:
impl PhysicsState {
pub fn edge_at(&self, edge_index: usize) -> &Edge {
&self.edges[edge_index]
}
pub fn node_at_mut(&mut self, node_index: usize) -> &mut Node {
&mut self.nodes[node_index]
}
fn remove_edge(&mut self, edge_index: usize) {
let edge = self.edge_at(edge_index); // first (immutable) borrow here
for i in 0..2 {
let node_index = edge.node_indices[i];
self.node_at_mut(node_index).remove_edge(edge_index); // second (mutable) borrow here -> ERROR
}
}
}
}
我原来用的是第一个版本,后来改成第二个,结果看到不行。
它失败对我来说是有道理的。 self
显然首先作为不可变借用,然后作为可变借用,正如预期的那样失败了。
我不明白的是:第一个版本是如何工作的?
很明显,第一次借用(获得 &Edge
)必须在整个 for 循环中保持有效,因为它在那里使用。但是它如何设法从 self
获得对 Node
的额外可变引用呢?
第二个版本的编译器返回的错误是:error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
为什么我在使用第一个版本时没有出现这个错误?
如果您想知道:
- Node 和 Edge 是简单的结构,没有实现复制,所以这不是这里发生的事情
- 我想切换到第二个版本的原因是那里的两个附加函数实际上包含要使用的类型转换,为了可读性我在这里删除了它,但我必须在每个地方重复我的代码没有这些功能。
也许我可以改用宏来达到同样的效果,但总的来说我只想知道这里的借用是如何工作的,因为在我看来我对此有某种误解。
谢谢!
您可以在第一个版本中借用 self.edges
并随后借用 self.nodes
的原因是因为编译器理解 self.edges
和 self.nodes
是单独借用的内容。这也是与结构相关的所谓“Splitting Borrows”。
但是,如果您不透明地查看方法签名:
fn edge_at(&self, edge_index: usize) -> &Edge
那你看看那个,你知道借的是什么吗?并不真地。只能看到returns&Edge
和&self
被借用了。因此 self
作为一个整体是被借用的,这不允许你进行 self.nodes
的后续可变借用,因为 self
已经被不可变地借用了。
您本质上希望发生的是调用方法允许 &self
被部分借用。这在 Rust 中不受支持。但是,有一个可追溯到 2015 年的 RFC 请求此功能。 RFC 标题为“Partial Borrowing (#1215)”,其中讨论了潜在的语法和语义。
第一个版本之所以有效,是因为在单个范围内,Rust 借用检查器可以更细粒度地“查看”借用,因此它可以判断何时从结构的不相交字段中借用引用,就像在您的示例中一样。
当你从 &self.edges[edge_index]
借用时,Rust 可以告诉不可变引用的生命周期与 self.edges
相关,而当你借用 self.nodes[node_index].remove_edge(edge_index)
时,Rust 可以告诉可变引用的生命周期与 self.edges
相关self.nodes
并且由于 self.edges
和 self.nodes
是不相交的结构字段,因此引用之间没有重叠,它们可以同时存在。
第二个例子失败了,因为你将单个作用域分解成多个作用域,现在 Rust 借用检查器只能根据你通过方法签名通知它的内容来推断引用的生命周期,以及第一个方法签名 fn edge_at(&self, edge_index: usize) -> &Edge
表示返回的引用的生命周期与 &self
相关,第二个方法签名 fn node_at_mut(&mut self, node_index: usize) -> &mut Node
表示返回的引用的生命周期与 &mut self
相关,现在当您在一个单一作用域 Rust 认为你有冲突的重叠引用,它们都是从 self
借用的(而不是像以前那样从 self.edges
和 self.nodes
借用的非重叠引用)所以它会抛出一个编译错误。
我有这个结构:
struct PhysicsState {
nodes: Vec<Node>,
edges: Vec<Edge>,
}
我正在尝试理解为什么这段代码可以编译:
impl PhysicsState {
fn remove_edge(&mut self, edge_index: usize) {
let edge = &self.edges[edge_index]; // first borrow here
// update the edge-index collection of the nodes connected by this edge
for i in 0..2 {
let node_index = edge.node_indices[i];
self.nodes[node_index].remove_edge(edge_index); // second (mutable) borrow here ?
}
}
}
虽然失败了:
impl PhysicsState {
pub fn edge_at(&self, edge_index: usize) -> &Edge {
&self.edges[edge_index]
}
pub fn node_at_mut(&mut self, node_index: usize) -> &mut Node {
&mut self.nodes[node_index]
}
fn remove_edge(&mut self, edge_index: usize) {
let edge = self.edge_at(edge_index); // first (immutable) borrow here
for i in 0..2 {
let node_index = edge.node_indices[i];
self.node_at_mut(node_index).remove_edge(edge_index); // second (mutable) borrow here -> ERROR
}
}
}
}
我原来用的是第一个版本,后来改成第二个,结果看到不行。
它失败对我来说是有道理的。 self
显然首先作为不可变借用,然后作为可变借用,正如预期的那样失败了。
我不明白的是:第一个版本是如何工作的?
很明显,第一次借用(获得 &Edge
)必须在整个 for 循环中保持有效,因为它在那里使用。但是它如何设法从 self
获得对 Node
的额外可变引用呢?
第二个版本的编译器返回的错误是:error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
为什么我在使用第一个版本时没有出现这个错误?
如果您想知道:
- Node 和 Edge 是简单的结构,没有实现复制,所以这不是这里发生的事情
- 我想切换到第二个版本的原因是那里的两个附加函数实际上包含要使用的类型转换,为了可读性我在这里删除了它,但我必须在每个地方重复我的代码没有这些功能。
也许我可以改用宏来达到同样的效果,但总的来说我只想知道这里的借用是如何工作的,因为在我看来我对此有某种误解。
谢谢!
您可以在第一个版本中借用 self.edges
并随后借用 self.nodes
的原因是因为编译器理解 self.edges
和 self.nodes
是单独借用的内容。这也是与结构相关的所谓“Splitting Borrows”。
但是,如果您不透明地查看方法签名:
fn edge_at(&self, edge_index: usize) -> &Edge
那你看看那个,你知道借的是什么吗?并不真地。只能看到returns&Edge
和&self
被借用了。因此 self
作为一个整体是被借用的,这不允许你进行 self.nodes
的后续可变借用,因为 self
已经被不可变地借用了。
您本质上希望发生的是调用方法允许 &self
被部分借用。这在 Rust 中不受支持。但是,有一个可追溯到 2015 年的 RFC 请求此功能。 RFC 标题为“Partial Borrowing (#1215)”,其中讨论了潜在的语法和语义。
第一个版本之所以有效,是因为在单个范围内,Rust 借用检查器可以更细粒度地“查看”借用,因此它可以判断何时从结构的不相交字段中借用引用,就像在您的示例中一样。
当你从 &self.edges[edge_index]
借用时,Rust 可以告诉不可变引用的生命周期与 self.edges
相关,而当你借用 self.nodes[node_index].remove_edge(edge_index)
时,Rust 可以告诉可变引用的生命周期与 self.edges
相关self.nodes
并且由于 self.edges
和 self.nodes
是不相交的结构字段,因此引用之间没有重叠,它们可以同时存在。
第二个例子失败了,因为你将单个作用域分解成多个作用域,现在 Rust 借用检查器只能根据你通过方法签名通知它的内容来推断引用的生命周期,以及第一个方法签名 fn edge_at(&self, edge_index: usize) -> &Edge
表示返回的引用的生命周期与 &self
相关,第二个方法签名 fn node_at_mut(&mut self, node_index: usize) -> &mut Node
表示返回的引用的生命周期与 &mut self
相关,现在当您在一个单一作用域 Rust 认为你有冲突的重叠引用,它们都是从 self
借用的(而不是像以前那样从 self.edges
和 self.nodes
借用的非重叠引用)所以它会抛出一个编译错误。