2016-10-15 6 views
4

Stringを含む構造体のIntoIterator特性を実装したいと思います。イテレータはchars()イテレータに基づいており、'1'の文字を数えてその結果を累積することになっています。これは私がこれまでに得たものの簡易版である:変更された `Chars`イテレータを使用したときの寿命パラメータの数が間違っています

use std::iter::Map; 
use std::str::Chars; 

fn main() { 
    let str_struct = StringStruct { system_string: String::from("1101") }; 
    for a in str_struct { 
     println!("{}", a); 
    } 
} 

struct StringStruct { 
    system_string: String 
} 

impl IntoIterator for StringStruct { 
    type Item = u32; 
    type IntoIter = Map<Chars, Fn(char) -> u32>; 

    fn into_iter(self) -> Self::IntoIter { 
     let count = 0; 
     return self.system_string.chars().map(|c| match c { 
      Some('1') => { 
       count += 1; 
       return Some(count); 
      }, 
      Some(chr) => return Some(count), 
      None => return None 
     }); 
    } 
} 

予想される出力:1, 2, 2, 3

これはで失敗します。

error[E0107]: wrong number of lifetime parameters: expected 1, found 0 
    --> src/main.rs:17:25 
    | 
17 |  type IntoIter = Map<Chars, Fn(char) -> u32>; 
    |       ^^^^^ expected 1 lifetime parameter 

文字のイテレータはStringStruct::system_stringと同じ寿命を持っている必要があり、しかし、私はこれをどう表現するのか、このアプローチが実用的かどうかは考えていません。

答えて

5

あなたが尋ねた質問に答えるために、私はimpl IntoIterator for &StringStructに(StringStructの代わりに、直接構造体への参照)をお勧めします。コードは次のようになります。

impl<'a> IntoIterator for &'a StringStruct { 
    type Item = u32; 
    type IntoIter = Map<Chars<'a>, Fn(char) -> u32>; 
    // ... 
} 

しかし、あなたはその後、異なる起源を持つ多くのより多くのエラーを気づくでしょう。ポップアップする次のエラーは、コンパイル時にFn(char) -> u32のサイズが一定でないことです。

問題は、Fn(char) -> u32と記述してクロージャのタイプを指定しようとしていることです。しかし、これはではありません。あなたのクロージャーのタイプですが、単にクロージャーによって実装される特性です。クロージャのタイプは、(「ボルデモートタイプ」とも呼ばれます)と命名することはできません。

これは、現在、Map<_, _>オブジェクトのタイプを指定できないことを意味します。これは既知の問題です。最近承認されたimpl Trait-RFCは、このような場合の回避策を提供する可能性があります。しかし、今は不可能です。申し訳ありません。

どのようにそれを解決するには?Iteratorを実装する独自の型を作成し、Map<_, _>の代わりに使用する必要があります。引き続きCharsイテレータを使用することができます。

struct StringStructIter<'a> { 
    chars: Chars<'a>, 
    count: u32, 
} 

impl<'a> Iterator for StringStructIter<'a> { 
    type Item = u32; 

    fn next(&mut self) -> Option<Self::Item> { 
     self.chars.next().map(|c| { 
      if c == '1' { 
       self.count += 1; 
      } 
      self.count 
     }) 
    } 
} 

impl<'a> IntoIterator for &'a StringStruct { 
    type Item = u32; 
    type IntoIter = StringStructIter<'a>; 

    fn into_iter(self) -> Self::IntoIter { 
     StringStructIter { 
      chars: self.system_string.chars(), 
      count: 0, 
     } 
    } 
} 

fn main() { 
    let str_struct = StringStruct { system_string: String::from("1101") }; 
    for a in &str_struct { 
     println!("{}", a); 
    } 
} 

そして、ちょうど小さなノート:ここに完全なソリューションですルーストに悪いスタイルと考えられている必要はありません明示的return。可能であればreturnを削除して慣用コードを書いてルールを書いてください。

+0

私はRustとnewbyです。ソリューションを使用するにはどうすればよいですか? 'のために??????? {println!( "{}"、a); } '? – LeMoussel

+0

私はあなたのソリューションをテストしたいが、私はこれを行う方法を見ていない。 'fn main(){ let str_struct = StringStructIter {" 1101 "からの操作方法は? }; for a str_struct { println!( "{}"、a); } } ' – LeMoussel

+0

@LeMoussel残りのコードを追加しました。 –

関連する問題