2017-02-15 10 views
4

変更可能なイテレータをサポートするおもちゃのコンテナクラスを設計したいと思いますが、イテレータのライフタイムとコンテナへの参照を並べ替えるのに問題があります。変更可能なイテレータをサポートするコンテナを実装するにはどうすればよいですか?

Iが最小非コンパイル例を作成するために試みた:

struct Payload { 
    value: i32, 
} 

struct Container { 
    val: Payload, 
} 

struct IterMut<'a> { 
    cont: &'a mut Container, 
    cnt: i32, 
} 

impl<'a> Container { 
    fn new() -> Container { 
     Container { val: Payload { value: 42 } } 
    } 
    fn iter_mut(&'a mut self) -> IterMut<'a> { 
     IterMut { 
      cont: self, 
      cnt: 10, 
     } 
    } 
} 

impl<'a> Iterator for IterMut<'a> { 
    type Item = &'a mut Payload; 

    fn next<'b>(&'b mut self) -> Option<Self::Item> { 
     self.cnt -= 1; 

     if self.cnt < 0 { 
      return None; 
     } else { 
      Some(&mut self.cont.val) 
     } 
    } 
} 

fn main() { 
    let mut cont = Container::new(); 

    let mut it = cont.iter_mut(); 
    it.next(); 
} 

上記iter_mut()を使用して上に反復するとき、同じアイテムを10回返す実際の愚かなコンテナを実装することが意図されています。

Iterator::nextの実装方法を理解できません。

私はnextのために何をしたいのと同じセマンティクスを実装して通常の関数の書き込みを管理しなかった:私はIterator::nextを実装するためにそれを適応させるために管理することができないので、これは助けない

fn manual_next<'a, 'b>(i: &'a mut IterMut<'b>) -> Option<&'a mut Payload> { 
    i.cnt -= 1; 

    if i.cnt < 0 { 
     return None; 
    } else { 
     Some(&mut i.cont.val) 
    } 
} 

を、 Iteratorを実装せずに、自分のコンテナをfor-loopsで繰り返し処理することはできません。

答えて

5

イテレータをそのまま実装することはできません。これは、同じアイテムに対する複数の変更可能な参照を取得し、Rustのエイリアシング/借用ルールを破ることができるためです。借りチェッカーがエラーをキャッチした良い事! :-)

たとえば、あなたのmain例拡張:

fn main() { 
    let mut cont = Container::new(); 

    let mut it = cont.iter_mut(); 
    let alias_1 = it.next(); 
    let alias_2 = it.next(); 
    // alias_1 and alias_2 both would have mutable references to cont.val! 
} 

その他iter_mutイテレータ(ベクトル/スライス上の1つの例のため)、各段階に異なるアイテムへの参照を返し、そうすることはありませんこの問題。

論理的に変更可能なものを繰り返し処理する必要がある場合は、永遠に反復することができますが、RefCellまたはCellで内部の変更を使用できます。

manual_next関数がコンパイルされる理由は、Iterator::nextシグニチャに制約されていないため、実際には一度だけ呼び出すことは完全に安全です(結果を保持しない場合はそれ以上)。

let mut cont = Container::new(); 

let mut it = cont.iter_mut(); 
let x = manual_next(&mut it); 
manual_next(&mut it); // Error: `it` is still borrowed mutably 
対照的に

Playground

Iterator::nextcollectがにINGのようなものを作るタイプがあります:あなたは結果を保存しようとした場合しかし、それはIterMutがmutably借りて、あなたは再びそれを呼び出すことができませんでした保ちます可能なベクトル。

+0

もちろん、ああ!だから私が本当に簡単な例を作成しようとしたとき、私は誤って無効な例を作りました。 –

+0

私の "マニュアル"ネクストメソッドが動作する理由は、そのシグネチャが同時に複数の戻り値を同時に生かすことができないためです。 Iterator-traitのnext-methodのシグネチャは何ですか? Iteratorの特性は、next()が同じ可変参照を2回返さないことを約束します。しかし、私の実装はまさにそうしようとしていました。 –

+1

はい、そうです。私はそれをカバーするために私の答えに少し追加しました。 –

関連する問題