我正在学习 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)
是的,你说得完全正确。该教程中实现的全部要点Drop
是避免递归调用,并且您的实现使用更少的代码(并且最后用更少的汇编)实现了相同的效果。
话虽如此,教程中的实现更加明确,并且可以说更容易看出发生了什么。确保mem::replace
被Link
替换Empty
,清楚地表明所有盒子也被丢弃。这可能是教程作者有意识的决定,也可能是疏忽。
奖金部分也可能提供关于作者想法的线索。他们简化Drop
实现的想法是添加一个对于简化其他方法也很有用的方法,因此仍然需要保持结构的完整性。事实上,这在Drop
实现中是不必要的,他们可能在考虑更大的情况时忽略了这一点,或者他们可能特别想要该实现,以便奖金部分有意义。
您的版本可能更高效,但可能需要再看一眼才能了解它真正在做什么。不过,我仍然会选择你的,因为它更短并且工作量更少。