Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Drop

ミュータブルリストと同様に、再帰的デストラクタ問題があります。 確かに、イミュータブルリストではこの問題はそこまで深刻ではありません。もし どこかの別のリストの head である別のノードに到達したとしても、それを 再帰的にドロップすることはありません。しかし、それでも気にかけるべき問題ではあり、 どう対処するかはそれほど明確ではありません。以前は次のように解決しました。

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();
        }
    }
}

問題はループの本体です。

cur_link = boxed_node.next.take();

これは Box の中にある Node を変更していますが、Rc ではそれはできません。Rc は 共有アクセスしか提供しないからです。任意の数の他の Rc がそれを指している可能性があります。

しかし、このノードを知っている最後のリストが自分たちだと分かっているなら、 実際には Rc から Node をムーブしても問題ありません。そうすれば、 いつ止めるべきかも分かります。Node を取り出せなくなったときです。

そして見てください。Rc にはまさにこれを行うメソッドがあります。try_unwrap です。

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;
            }
        }
    }
}
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

素晴らしい! いいですね。