2017-02-24 17 views
2

私はタイプのベクトルのための可変イテレータを作成しようとしています:Vec<Vec<(K, V)>>変更可能なイテレータ>

反復子コード:

pub struct IterMut<'a, K: 'a, V: 'a> { 
    iter: &'a mut Vec<Vec<(K, V)>>, 
    ix: usize, 
    inner_ix: usize, 
} 

impl<'a, K, V> Iterator for IterMut<'a, K, V> { 
    type Item = (&'a K, &'a mut V); 

    #[inline] 
    fn next(&mut self) -> Option<(&'a K, &'a mut V)> { 

     while self.iter.len() < self.ix { 
      while self.iter[self.ix].len() < self.inner_ix { 
       self.inner_ix += 1; 
       let (ref k, ref mut v) = self.iter[self.ix][self.inner_ix]; 
       return Some((&k, &mut v)); 
      } 

      self.ix += 1; 
     } 

     return None; 
    } 
} 

私が手にエラーがある:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements 
    --> src/main.rs:16:42 
    | 
16 |     let (ref k, ref mut v) = self.iter[self.ix][self.inner_ix]; 
    |           ^^^^^^^^^^^^^^^^^^ 
    | 
help: consider using an explicit lifetime parameter as shown: fn next(&'a mut self) -> Option<(&'a K, &'a mut V)> 
    --> src/main.rs:11:5 
    | 
11 |  fn next(&mut self) -> Option<(&'a K, &'a mut V)> { 
    | ^

明らかに私は生涯の問題を抱えていますが、これがうまくいくはずであることをコンパイラーに伝える方法はわかりません。

これは、どのように変更可能なイテレータを実装すべきか、それとも良い方法ですか?

答えて

6

わかりにくいエラーメッセージをデバッグする際には、問題をできるだけ簡単に解決してください。

最初のステップは、その本質的な構成要素への発現を破るのは、インデックス手順を分割することによって開始させることです。

Index形質は、その出力の寿命はその受信機のそれにリンクされていることを前提としてい
fn next(&mut self) -> Option<(&'a K, &'a mut V)> { 

    while self.iter.len() < self.ix { 
     while self.iter[self.ix].len() < self.inner_ix { 
      self.inner_ix += 1; 
      let outer: &'a mut Vec<_> = self.iter; 
      let inner: &'a mut Vec<_> = &mut outer[self.ix]; 
      let (ref k, ref mut v) = inner[self.inner_ix]; 
      return Some((&k, &mut v)); 
     } 

     self.ix += 1; 
    } 

    return None; 
} 

、したがって'aの生涯を得るためには、受信者は&'aの生涯を持つ必要があり、それは上方に伝播して上記のコードにつながります。

ただし、ここに問題があります:let outer: &'a mut Vec<_> = self.iter;は、可変参照がCopyではないため、コンパイルできません。

可変参照からどのように可変参照を取得するのですか(IndexMutは可変参照を取得するので可能でしょう)。

1つは再借用を使用します:let outer: &'a mut Vec<_> = &mut *self.iter;

そして、オハイオ州:

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements 
    --> <anon>:16:45 
    | 
16 |     let outer: &'a mut Vec<_> = &mut *self.iter; 
    |            ^^^^^^^^^^^^^^^ 
    | 

reborrowed参照が'aには有効ではありませんが、それだけでselfの(名前の)存続のために有効なのです!

なぜ錆ですか?どうして?

そうしないと、危険です。

&mut Tは(あなたがインデックスを進めるために忘れてしまった場合)しかし、あなたの方法は、エイリアシングの参照を作成することができ、エイリアシングしないことが保証されています

#[inline] 
fn next(&mut self) -> Option<(&'a K, &'a mut V)> { 
    let (ref k, ref mut v) = self.iter[self.ix][self.inner_ix]; 
    return Some((&k, &mut v)); 
} 

をそして、あなたがいない場合でも、あなたのドンことが保証していません"ステップバック"を可能にする方法はrewindです。

TL; DR:あなたは、あなたの代わりにスタックオーバーフローに向かって操縦された地雷を踏むことを約あった。)あなたはイテレータを実装するのですか


よしのが、

もちろん、イテレータを使用します。 Shepmaster(簡潔に)が答えると、すでに標準ライブラリに相当するものがFlatMapと見なされます。このトリックは、既存のイテレーターを使って細かいディテールを作成することです!以下のような

何か:あなたはouterからそれを補充する際に空

use std::slice::IterMut; 

pub struct MyIterMut<'a, K: 'a, V: 'a> { 
    outer: IterMut<'a, Vec<(K, V)>>, 
    inner: IterMut<'a, (K, V)>, 
} 

は、次に、あなたがいる限り、それはアイテムを提供してinnerから消費、および。

impl<'a, K, V> MyIterMut<'a, K, V> { 
    fn new(v: &'a mut Vec<Vec<(K, V)>>) -> MyIterMut<'a, K, V> { 
     let mut outer = v.iter_mut(); 
     let inner = outer.next() 
         .map(|v| v.iter_mut()) 
         .unwrap_or_else(|| (&mut []).iter_mut()); 
     MyIterMut { outer: outer, inner: inner } 
    } 
} 

impl<'a, K, V> Iterator for MyIterMut<'a, K, V> { 
    type Item = (&'a K, &'a mut V); 

    #[inline] 
    fn next(&mut self) -> Option<(&'a K, &'a mut V)> { 
     loop { 
      match self.inner.next() { 
       Some(r) => return Some((&r.0, &mut r.1)), 
       None =>(), 
      } 

      match self.outer.next() { 
       Some(v) => self.inner = v.iter_mut(), 
       None => return None, 
      } 
     } 
    } 
} 

簡単なテストケース:

fn main() { 
    let mut v = vec![ 
     vec![(1, "1"), (2, "2")], 
     vec![], 
     vec![(3, "3")] 
    ]; 
    let iter = MyIterMut::new(&mut v); 
    let c: Vec<_> = iter.collect(); 
    println!("{:?}", c); 
} 

プリント:

[(1, "1"), (2, "2"), (3, "3")] 
それは完全に壊れていないので、予想通り

、が、私は私が頼る必要はありませんでした望みます&[]'staticトリックです(つまり、std::slice::IterMutDefault)。

+0

うわー!ありがとう!これは本当に素晴らしい答えです!私は実際にカスタムハッシュマップに取り組んでいます。 –

+0

'unwrap_or_else(...)'は 'outer'が空の場合に使用されますか? –

+1

@JesperAxelsson:そうです。しかし、私は、空のスライスへの変更可能な参照が ''静的な存続期間を持つことができるというトリックを使用して、安全でないコードを使用しないようにそのビットを更新しました。 @MatthieuMはこのことについて知らなかった。 :) –

3

あなたは標準Iterator::flat_mapを再実装している理由は設けられていないてきたので、私はちょうどあなたが必要としない可変性を削除することや、別のmapを使用したい:

fn main() { 
    let mut a: Vec<Vec<(u8, u8)>> = Default::default(); 
    let c = a.iter_mut() 
     .flat_map(|x| x.iter_mut()) 
     .map(|&mut (ref a, ref mut b)| (a, b)) 
     .count(); 
    println!("{}", c); 
} 

あなたがいることを持っていたら、ちょうどreturn the iterator in one of the many waysです。

+0

ありがとうございます!私は、Iteratorをどのように渡すのかと不思議に思っていて、将来的には役に立つでしょう。 –

関連する問題