我可以在同一个函数中从 &mut self 移动到 &self 吗?
Can I move from &mut self to &self within the same function?
我正在尝试通过一个玩具应用程序学习一点 Rust,它涉及一个通过查询外部源动态填充的树数据结构。一开始,只有根节点存在。树结构提供了一种方法get_children(id)
,即returns一个[u32]
所有节点的子节点的ID——要么这个数据是已知的,要么查询外部源,所有节点都是插入到树中。
我 运行 遇到了以下我似乎无法弄清楚的借用检查器问题:
struct Node {
id: u32,
value: u64, // in my use case, this type is much larger and should not be copied
children: Option<Vec<u32>>,
}
struct Tree {
nodes: std::collections::HashMap<u32, Node>,
}
impl Tree {
fn get_children(&mut self, id: u32) -> Option<&[u32]> {
// This will perform external queries and add new nodes to the tree
None
}
fn first_even_child(&mut self, id: u32) -> Option<u32> {
let children = self.get_children(id)?;
let result = children.iter().find(|&id| self.nodes.get(id).unwrap().value % 2 == 0)?;
Some(*result)
}
}
这导致:
error[E0502]: cannot borrow `self.nodes` as immutable because it is also borrowed as mutable
--> src/lib.rs:19:43
|
18 | let children = self.get_children(id)?;
| ---- mutable borrow occurs here
19 | let result = children.iter().find(|&id| self.nodes.get(id).unwrap().value % 2 == 0)?;
| ---- ^^^^^ ---------- second borrow occurs due to use of `self.nodes` in closure
| | |
| | immutable borrow occurs here
| mutable borrow later used by call
由于 get_children
可能会向树中插入节点,因此我们需要一个 &mut self
引用。然而,在我看来,children
的值已知后,self
不再需要可变借用。为什么这不起作用,我该如何解决?
编辑——我的解决方法
在 Chayim Friedman 的回答后,我决定不返回 Self
。当首先调用 get_children
获取 ID 列表,然后使用 nodes.get()
获取相应的 Node
时,我主要 运行 遇到了上述问题。相反,我重构以提供以下功能:
impl Tree {
fn load_children(&mut self, id: u32) {
// If not present yet, perform queries to add children to the tree
}
fn iter_children(&self, id: u32) -> Option<IterChildren> {
// Provides an iterator over the children of node `id`
}
}
将可变引用降级为共享引用会生成一个应保持唯一的引用。这是必要的,例如Cell::from_mut()
,具有以下签名:
pub fn from_mut(t: &mut T) -> &Cell<T>
此方法依赖于 &mut T
的唯一性保证,以确保仅通过 Cell
直接保留对 T
的引用。如果降级引用意味着可能违反了唯一性,则此方法将是不合理的,因为 Cell
中的值可能已被另一个共享引用更改(通过内部可变性)。
有关此内容的更多信息,请参阅 Common Rust Lifetime Misconceptions: downgrading mut refs to shared refs is safe。
要解决这个问题,您需要从从可变引用创建的同一个共享引用中获取两个共享引用。例如,您还可以从 get_children()
:
return &Self
fn get_children(&mut self, id: u32) -> Option<(&Self, &[u32])> {
// This will perform external queries and add new nodes to the tree
Some((self, &[]))
}
fn first_even_child(&mut self, id: u32) -> Option<u32> {
let (this, children) = self.get_children(id)?;
let result = children.iter().find(|&id| this.nodes.get(id).unwrap().value % 2 == 0)?;
Some(*result)
}
我正在尝试通过一个玩具应用程序学习一点 Rust,它涉及一个通过查询外部源动态填充的树数据结构。一开始,只有根节点存在。树结构提供了一种方法get_children(id)
,即returns一个[u32]
所有节点的子节点的ID——要么这个数据是已知的,要么查询外部源,所有节点都是插入到树中。
我 运行 遇到了以下我似乎无法弄清楚的借用检查器问题:
struct Node {
id: u32,
value: u64, // in my use case, this type is much larger and should not be copied
children: Option<Vec<u32>>,
}
struct Tree {
nodes: std::collections::HashMap<u32, Node>,
}
impl Tree {
fn get_children(&mut self, id: u32) -> Option<&[u32]> {
// This will perform external queries and add new nodes to the tree
None
}
fn first_even_child(&mut self, id: u32) -> Option<u32> {
let children = self.get_children(id)?;
let result = children.iter().find(|&id| self.nodes.get(id).unwrap().value % 2 == 0)?;
Some(*result)
}
}
这导致:
error[E0502]: cannot borrow `self.nodes` as immutable because it is also borrowed as mutable
--> src/lib.rs:19:43
|
18 | let children = self.get_children(id)?;
| ---- mutable borrow occurs here
19 | let result = children.iter().find(|&id| self.nodes.get(id).unwrap().value % 2 == 0)?;
| ---- ^^^^^ ---------- second borrow occurs due to use of `self.nodes` in closure
| | |
| | immutable borrow occurs here
| mutable borrow later used by call
由于 get_children
可能会向树中插入节点,因此我们需要一个 &mut self
引用。然而,在我看来,children
的值已知后,self
不再需要可变借用。为什么这不起作用,我该如何解决?
编辑——我的解决方法
在 Chayim Friedman 的回答后,我决定不返回 Self
。当首先调用 get_children
获取 ID 列表,然后使用 nodes.get()
获取相应的 Node
时,我主要 运行 遇到了上述问题。相反,我重构以提供以下功能:
impl Tree {
fn load_children(&mut self, id: u32) {
// If not present yet, perform queries to add children to the tree
}
fn iter_children(&self, id: u32) -> Option<IterChildren> {
// Provides an iterator over the children of node `id`
}
}
将可变引用降级为共享引用会生成一个应保持唯一的引用。这是必要的,例如Cell::from_mut()
,具有以下签名:
pub fn from_mut(t: &mut T) -> &Cell<T>
此方法依赖于 &mut T
的唯一性保证,以确保仅通过 Cell
直接保留对 T
的引用。如果降级引用意味着可能违反了唯一性,则此方法将是不合理的,因为 Cell
中的值可能已被另一个共享引用更改(通过内部可变性)。
有关此内容的更多信息,请参阅 Common Rust Lifetime Misconceptions: downgrading mut refs to shared refs is safe。
要解决这个问题,您需要从从可变引用创建的同一个共享引用中获取两个共享引用。例如,您还可以从 get_children()
:
&Self
fn get_children(&mut self, id: u32) -> Option<(&Self, &[u32])> {
// This will perform external queries and add new nodes to the tree
Some((self, &[]))
}
fn first_even_child(&mut self, id: u32) -> Option<u32> {
let (this, children) = self.get_children(id)?;
let result = children.iter().find(|&id| this.nodes.get(id).unwrap().value % 2 == 0)?;
Some(*result)
}