2016-10-15 1 views
4

Je souhaite implémenter le trait IntoIterator pour une structure contenant un String. L'itérateur est basé sur l'itérateur chars(), est censé compter les caractères '1' et accumuler le résultat. Ceci est une version simplifiée de ce que je suis arrivé à ce jour:Mauvais nombre de paramètres de durée de vie lors de l'utilisation d'un itérateur `Chars 'modifié

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

Sortie prévue: 1, 2, 2, 3

Cela échoue avec:

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 

Le caractère iterator doit avoir la même vie que le StringStruct::system_string, mais je n'ai aucune idée de comment l'exprimer ou si cette approche est viable du tout.

Répondre

5

Pour répondre à la question que vous avez posée, je vous recommande de impl IntoIterator for &StringStruct (une référence à un StringStruct au lieu du struct directement). Le code ressemblerait à ceci:

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

Cependant, vous remarquerez de nombreuses erreurs plus qui ont une origine différente par la suite. L'erreur suivante qui apparaît est que Fn(char) -> u32 n'a pas une taille constante au moment de la compilation.

Le problème est que vous essayez de nommer le type de votre fermeture en écrivant Fn(char) -> u32. Mais c'est pas le type de votre fermeture, mais simplement un trait qui est mis en œuvre par la fermeture. Le type d'une fermeture ne peut pas être nommé (parfois appelé "type Voldemort").

Cela signifie que, pour le moment, vous ne pouvez pas spécifier le type d'un objet Map<_, _>. C'est un problème connu; le impl Trait -RFC récemment accepté pourrait offrir une solution de contournement pour les cas comme celui-ci. Mais maintenant, ce n'est pas possible, désolé.

Alors, comment le résoudre alors? Vous devez créer votre propre type qui implémente Iterator et l'utiliser au lieu de Map<_, _>. Notez que vous pouvez toujours utiliser l'itérateur Chars. Voici la solution complète:

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

Et juste une petite note: un return explicite lorsqu'ils ne sont pas nécessaires est considéré comme mauvais style à Rust. Mieux vaut s'en tenir à la règle et écrire le code idiomatique en supprimant return autant que possible ;-)

+0

Je suis nouveau avec Rust. Comment puis-je utiliser votre solution? 'pour un ?????? {println! ("{}", a); } '? – LeMoussel

+0

Je veux tester votre solution mais je ne vois pas comment faire. 'fn main() { let str_struct = StringStructIter {Comment faire à partir de" 1101 "? } pour un str_struct { println! ("{}", A); } } ' – LeMoussel

+0

@LeMoussel J'ai ajouté le code restant, j'espère que tout devrait être clair maintenant! –