3.3 Drop

原文链接: https://rust-unofficial.github.io/too-many-lists/third-drop.html

和可变链表一样,我们有递归析构问题。对不可变链表来说这没那么糟:若遇到某处另一链表的头节点,我们不会递归 drop 它。但仍值得关注,而且怎么处理不那么明显。之前是这样解决的:

1
2
3
4
5
6
7
8
impl<T> Drop for List<T> {
    fn drop(&mut self) {
        let mut cur_link = self.head.take();
        while let Some(mut boxed_node) = cur_link {
            cur_link = boxed_node.next.take();
        }
    }
}

问题在循环体:

1
cur_link = boxed_node.next.take();

这是在变异 Box 里的 Node,但 Rc 不行;它只给共享访问,因为可能有很多其他 Rc 指向它。

但若我们知道自己是最后一个还知道这个节点的链表,从 Rc 里移出 Node 其实没问题。也能知道何时停止:每当无法把 Node 取出来时。

看,Rc 有正好做这事的方法:try_unwrap:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
impl<T> Drop for List<T> {
    fn drop(&mut self) {
        let mut head = self.head.take();
        while let Some(node) = head {
            if let Ok(mut node) = Rc::try_unwrap(node) {
                head = node.next.take();
            } else {
                break;
            }
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
cargo test
   Compiling lists v0.1.0 (/Users/ADesires/dev/too-many-lists/lists)
    Finished dev [unoptimized + debuginfo] target(s) in 1.10s
     Running /Users/ADesires/dev/too-many-lists/lists/target/debug/deps/lists-86544f1d97438f1f

running 8 tests
test first::test::basics ... ok
test second::test::basics ... ok
test second::test::into_iter ... ok
test second::test::iter ... ok
test second::test::iter_mut ... ok
test second::test::peek ... ok
test third::test::basics ... ok
test third::test::iter ... ok

test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

很好! 不错。

最后修改 August 23, 2026: 更新 (499855b16)