单链表的这两个 drop 实现之间是否有任何区别

Hri*_*ram 8 rust

我正在学习 Rust with Entirely Too Many Linked Lists并且有一个关于该书中初始链表的 drop 实现的问题。链表由堆栈分配的链接组成,该链接要么是空的,要么指向带有一些关联数据的堆分配的节点。

struct List {
    head: Link,
}

enum Link {
    Empty,
    More(Box<Node>),
}

struct Node {
    data: i32,
    next: Link,
}
Run Code Online (Sandbox Code Playgroud)

书中给出的 drop trait 的实现std::mem::replace用于获取列表中节点的所有权。

// Copied from the book, omitting comments
impl Drop for List {
    fn drop(&mut self) {
        let mut cur_link = mem::replace(&mut self.head, Link::Empty);
        while let Link::More(mut boxed_node) = cur_link {
            cur_link = mem::replace(&mut boxed_node.next, Link::Empty);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我很困惑为什么这本书使用mem::replace来获得节点的下一个指针的所有权。似乎我们已经拥有boxed_node来自该while let行的所有权,我们可以将 cur_link 设置为node.next而不是使用mem::replace.

我写了这个替代实现,它编译得很好。我想知道这两种 drop 方法之间是否有任何区别。

impl Drop for List {
    fn drop(&mut self) {
        let mut link = mem::replace(&mut self.head, Link::Empty);
        while let Link::More(node) = link {
            link = node.next;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Pet*_*all 2

是的,你说得完全正确。该教程中实现的全部要点Drop是避免递归调用,并且您的实现使用更少的代码(并且最后用更少的汇编)实现了相同的效果。

话虽如此,教程中的实现更加明确,并且可以说更容易看出发生了什么。确保mem::replaceLink替换Empty,清楚地表明所有盒子也被丢弃。这可能是教程作者有意识的决定,也可能是疏忽。

奖金部分也可能提供关于作者想法的线索。他们简化Drop实现的想法是添加一个对于简化其他方法也很有用的方法,因此仍然需要保持结构的完整性。事实上,这在Drop实现中是不必要的,他们可能在考虑更大的情况时忽略了这一点,或者他们可能特别想要该实现,以便奖金部分有意义。

您的版本可能更高效,但可能需要再看一眼才能了解它真正在做什么。不过,我仍然会选择你的,因为它更短并且工作量更少。