我正在尝试在Rust中实现二进制搜索树,我遇到插入元素的问题。在Rust中这样做的惯用方法是什么?
这是我的实施:
use std::cmp::Ordering;
pub struct BinarySearchTree {
root: OptNode,
size: u32,
}
type OptNode = Option<Box<Node>>;
struct Node {
key: i32,
left: OptNode,
right: OptNode,
}
impl BinarySearchTree {
pub fn new() -> Self {
BinarySearchTree {
root: None,
size: 0,
}
}
pub fn is_empty(&self) -> bool {
self.size == 0
}
pub fn size(&self) -> u32 {
self.size
}
pub fn contains(&self, key: i32) -> bool {
let mut node = &self.root;
while let Some(ref boxed_node) = *node {
match key.cmp(&boxed_node.key) {
Ordering::Less => node = &boxed_node.left,
Ordering::Greater => node = &boxed_node.right,
Ordering::Equal => return true,
}
}
false
}
pub fn insert(&mut self, key: i32) {
let mut node = &mut self.root;
while let Some(ref mut boxed_node) = *node {
match key.cmp(&boxed_node.key) {
Ordering::Less => node = &mut boxed_node.left,
Ordering::Greater => node = &mut boxed_node.right,
Ordering::Equal => return,
}
}
*node = Some(Box::new(Node {
key: key,
left: None,
right: None,
}));
}
}
fn main() {}
以下是我遇到的错误:
error[E0499]: cannot borrow `node.0` as mutable more than once at a time
--> src/main.rs:47:24
|
47 | while let Some(ref mut boxed_node) = *node {
| ^^^^^^^^^^^^^^^^^^ mutable borrow starts here in previous iteration of loop
...
60 | }
| - mutable borrow ends here
error[E0506]: cannot assign to `node` because it is borrowed
--> src/main.rs:49:35
|
47 | while let Some(ref mut boxed_node) = *node {
| ------------------ borrow of `node` occurs here
48 | match key.cmp(&boxed_node.key) {
49 | Ordering::Less => node = &mut boxed_node.left,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `node` occurs here
error[E0506]: cannot assign to `node` because it is borrowed
--> src/main.rs:50:38
|
47 | while let Some(ref mut boxed_node) = *node {
| ------------------ borrow of `node` occurs here
...
50 | Ordering::Greater => node = &mut boxed_node.right,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `node` occurs here
error[E0506]: cannot assign to `*node` because it is borrowed
--> src/main.rs:55:9
|
47 | while let Some(ref mut boxed_node) = *node {
| ------------------ borrow of `*node` occurs here
...
55 | / *node = Some(Box::new(Node {
56 | | key: key,
57 | | left: None,
58 | | right: None,
59 | | }));
| |___________^ assignment to borrowed `*node` occurs here
答案 0 :(得分:4)
Rust的编译器还不够复杂(但是?)来处理这种情况。 Rust看到你试图不止一次地多次尝试借用相同的值,因为它在循环中看到对同一个变量的重复可变借位。当然,这并不是你想要做的事情,因为你想在每次迭代时重新分配变量,但Rust并不支持分配给被借用的变量。
我们需要做的是拥有中间变量,以便编译器可以正确地跟踪借用。我们如何创建不确定数量的变量?随着递归!
impl BinarySearchTree {
pub fn insert(&mut self, key: i32) {
fn insert_node(node: &mut OptNode, key: i32) {
if let Some(ref mut boxed_node) = *node {
match key.cmp(&boxed_node.key) {
Ordering::Less => insert_node(&mut boxed_node.left, key),
Ordering::Greater => insert_node(&mut boxed_node.right, key),
Ordering::Equal => return,
}
} else {
*node = Some(Box::new(Node { key: key, left: None, right: None}));
}
}
insert_node(&mut self.root, key)
}
}
注意:虽然这个算法是尾递归的,但是Rust并没有将它优化为尾调用,所以它可能会在退化情况下导致堆栈溢出。
答案 1 :(得分:3)
没有递归:
pub fn insert(&mut self, key: i32) {
let mut node = &mut self.root;
loop {
node = match node.as_ref().map(|n| key.cmp(&n.key)) {
Some(Ordering::Less) => &mut { node }.as_mut().unwrap().left,
Some(Ordering::Equal) => return,
Some(Ordering::Greater) => &mut { node }.as_mut().unwrap().right,
None => {
*node = Some(Box::new(Node {
key: key,
left: None,
right: None,
}));
return;
}
};
}
}
unwrap()
在这里很安全。
请您详细说明
{node}.as_mut()...
工作的原因
node
是一个可变引用(&mut Option<Box<Node>>
)。它无法复制。
let temp = node;
此处node
被移动到temp
。这正是我们需要避免分配给借来的node
。我们可以移动 node
到新的临时变量并借用它。
// ...
Some(Ordering::Less) => {
let temp = node;
&mut temp.as_mut().unwrap().left
}
// ...
紧凑符号:
// ...
Some(Ordering::Less) => &mut { let temp = node; temp }.as_mut().unwrap().left,
// ...
表达式{ node }
和{ let temp = node; temp }
是等效的,但在第一种情况下,node
将移动到隐式临时变量。
答案 2 :(得分:1)
Rust的编译器不够复杂(但是?)
即将来临,它被称为non-lexical lifetimes。启用它们后,您的原始代码将按原样运行:
#![feature(nll)]
use std::cmp::Ordering;
pub struct BinarySearchTree {
root: OptNode,
size: u32,
}
type OptNode = Option<Box<Node>>;
struct Node {
key: i32,
left: OptNode,
right: OptNode,
}
impl BinarySearchTree {
pub fn new() -> Self {
BinarySearchTree {
root: None,
size: 0,
}
}
pub fn is_empty(&self) -> bool {
self.size == 0
}
pub fn size(&self) -> u32 {
self.size
}
pub fn contains(&self, key: i32) -> bool {
let mut node = &self.root;
while let Some(ref boxed_node) = *node {
match key.cmp(&boxed_node.key) {
Ordering::Less => node = &boxed_node.left,
Ordering::Greater => node = &boxed_node.right,
Ordering::Equal => return true,
}
}
false
}
pub fn insert(&mut self, key: i32) {
let mut node = &mut self.root;
while let Some(ref mut boxed_node) = *node {
match key.cmp(&boxed_node.key) {
Ordering::Less => node = &mut boxed_node.left,
Ordering::Greater => node = &mut boxed_node.right,
Ordering::Equal => return,
}
}
*node = Some(Box::new(Node {
key: key,
left: None,
right: None,
}));
}
}
fn main() {}