我对Rust还不太熟悉,想实现一个AVL树。
我使用以下枚举来表示我的树:

enum AvlTree<T> {
    Leaf,
    Node {
        left: Box<AvlTree<T>>,
        right: Box<AvlTree<T>>,
        value: T
    }
}

在实现其中一个平衡功能时,我面临所有权和借款方面的一些问题。
我试图编写一个函数,它接受一个AvlTree<T>并返回另一个AvlTree<T>。我的第一次尝试是这样的:
fn balance_ll(tree: AvlTree<T>) -> AvlTree<T> {
    if let AvlTree::Node {left: t, right: u, value: v} = tree {
        if let AvlTree::Node {left: ref tl, right: ref ul, value: ref vl} = *t {
            AvlTree::Leaf // Return a new AvlTree here
        } else {
            tree
        }
    } else {
        tree
    }
}

即使使用这个最小的示例,编译器仍返回一个错误:
error[E0382]: use of partially moved value: `tree`
  --> avl.rs:67:17
   |
63 |         if let AvlTree::Node {left: t, right: u, value: v} = tree {
   |                                     - value moved here
...
67 |                 tree
   |                 ^^^^ value used here after move
   |
   = note: move occurs because `(tree:AvlTree::Node).left` has type `std::boxed::Box<AvlTree<T>>`, which does not implement the `Copy` trait

我认为,我正确地理解了错误消息,在这种解构中AvlTree::Node将夺走树示例的所有权。我怎样才能防止这种情况发生?我已经尝试了各种方法,并且(去)引用tree-变量,只为了面对更多的错误。
另外,我想在新结构中使用一些提取的值,如utlvl。这有可能吗?你能举一个很小的例子吗?在执行函数之后,我不需要访问旧树。

最佳答案

我认为,我正确地理解了错误消息,在这种解构中AvlTree::Node将夺走树示例的所有权。
对。如果您以后仍然需要使用tree,则需要复制它:

#[derive(Clone)]
enum AvlTree<T> {...}

fn balance_ll<T: Clone>(tree: AvlTree<T>) -> AvlTree<T> {
    let copy = tree.clone();

    if let AvlTree::Node { left: t, right: u, value: v } = tree {
        if let AvlTree::Node { left: ref tl, right: ref ul, value: ref vl } = *t {
            AvlTree::Leaf // Return a new AvlTree here
        } else {
            copy
        }
    } else {
        tree
    }
}

或者使用一个帮助函数来快速释放它的所有权-但是我认为没有框模式是不可能的:
#![feature(box_patterns)]

impl<T> AvlTree<T> {
    fn is_left_node(&self) -> bool {
        if let &AvlTree::Node { left: ref t, right: ref u, value: ref v } = self {
            if let &box AvlTree::Node { left: ref tl, right: ref ul, value: ref vl } = t {
                true
            } else {
                false
            }
        } else {
            false
        }
    }
}

fn balance_ll<T>(tree: AvlTree<T>) -> AvlTree<T> {
    if tree.is_left_node() {
        AvlTree::Leaf
    } else {
        tree
    }
}

因为您可能希望使用解构值,所以您可能更喜欢clone变量,但另一个变量可能会给您一些额外的想法。

07-25 20:37