2015-01-11 4 views
8

表面では、draininto_iterの両方が、同様のイテレータ、つまりコレクションの値を提供しているように見えます。しかし、彼らは異なっている:いつ `drain`対` into_iter`を使うべきですか?

fn main() { 
    let mut items1 = vec![0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9]; 
    let items2 = items1.clone(); 

    println!("{:?}", items1.drain().count()); 
    println!("{:?}", items2.into_iter().count()); 

    println!("{:?}", items1); 
    // println!("{:?}", items2); Moved 
} 

drainコレクションに&mutを取り、コレクションはその後使用可能です。 into_iterはコレクションを消費します。各イテレータの適切な用途は何ですか?

答えて

8

これらはお互いにある程度冗長です。しかし、あなたが言うように、Drainはベクトルを借りるだけです。特に、ベクトルに接続された有効期間があります。イテレータを返すか、可能であれば最も柔軟な方法でイテレータを作成したい場合は、Vecのオーナーにチェーンされていないので、into_iterを使用する方が良いでしょう。データ構造を再利用する(例えば、割り当てを再利用する)場合には、drainがこれを行う最も直接的な方法である。

また、(やや)理論的な懸念はしばらく、Drainはどちらか、つまり、元の構造は、それが何であれタイプの有効なインスタンスであることにつながる不変量を維持、または最後にそれらを修正するを必要としていることですIntoIterは、値を完全に制御しているので、好きなだけ構造をマングリングすることができます。

この小さな、現実世界の例では、すでにstdでありますので、私は唯一の「やや」理論と言う:HashMapはまた、これらのメソッドを持っているその内部RawTable種類、経由.drain.into_iterを公開します。 into_iterはちょうどread the hash of the value being moved directlyとすることができますが、drainはそれを読むだけでなく、慎重にto update the hash to indicate that the cell is then emptyにする必要があります。明らかに、これはこのインスタンス(おそらく1つまたは2つの追加の命令)では絶対に小さいですが、ツリーのようなより複雑なデータ構造の場合、データ構造の不変量を破ることから得られるいくつかの些細な利益があるかもしれません。

7

drainを使用した後、Vecは空ですが、その要素に以前に割り当てられた記憶域は割り当てられたままです。つまり、Vecに新しい要素を挿入するには、Veccapacityに達するまで記憶域を割り当てる必要がありません。

もう一度Vecを使用する前に、Drainイテレータへのすべての参照を削除する必要があります。 Drainの実装がDropの場合、まだ削除されていない要素はすべて削除されるため、Vecは、繰り返し処理を完了しなくても空になります。

関連する問題