2015-07-22 1 views
4

Je dois mettre en œuvre la méthode iter, qui renvoie quelque chose qui implémente le trait Iterator<Item = char>. Mais la valeur de retour sera différente implémentations, en fonction de la variante enum.Comment implémenter la méthode iter en utilisant la répartition statique/dynamique?

Quelque chose comme ceci:

pub enum Class { 
    SingleChar(char), 
    Range(Range), 
    And(Vec<Class>), 
    Or(Vec<Class>), 
} 

impl Class { 
    pub fn iter(&self) -> Iterator<Item = char> { 
     match *self { 
      Class::SingleChar(c) => vec![c], 
      Class::Range(ref range) => range.iter(), 
      Class::And(ref classes) => { 
       let iter: Option<_> = classes.iter().fold(None, |iter, &class| { 
        match iter { 
         None => Some(class.iter()), 
         Some(iter) => Some(iter.merge(class.iter())), 
        } 
       }); 
       Box::new(iter.unwrap()) 
      }, 
      Class::Or(ref classes) => { 
       let iter: Option<_> = classes.iter().fold(None, |iter, &class| { 
        match iter { 
         None => Some(class.iter()), 
         Some(iter) => Some(iter.interleave(class.iter())), 
        } 
       }); 
       Box::new(iter.unwrap()) 
      }, 
     } 
    } 
} 

range.iter() renvoie une struct qui implémente Iterator<Item=char>.

merge et interleave sont des méthodes itertools, qui reviennent MergeAscend et Interleave respectivement (les deux mettre en œuvre Iterator<Item=char>)

  1. Comment mettre en œuvre un tel système de dispatch statique?
  2. Si la répartition statique n'est pas possible, comment implémenter un tel schéma en utilisant la répartition dynamique?

Répondre

3

Il n'est pas possible de le faire en utilisant la répartition statique. Il y a un tracking RFC issue sur les types de retour abstraits sans boîte, mais Rust n'est pas encore là (et je ne suis pas sûr qu'il pourrait couvrir le cas d'utilisation de renvoyer différents types). Par conséquent, l'envoi dynamique est la voie à suivre.

Vous êtes assez proche, en fait. Il suffit de faire le type de retour Box<Iterator<Item=char>> et ajouter la boxe:

pub fn iter(&self) -> Box<Iterator<Item=char>> { 
    match *self { 
     Class::SingleChar(c) => Box::new(Some(c).into_iter()), 
     Class::Range(ref range) => Box::new(range.iter()), 
     Class::And(ref classes) => { 
      let iter: Option<_> = classes.iter().fold(None, |iter, &class| { 
       match iter { 
        None => Some(Box::new(class.iter())), 
        Some(iter) => Some(Box::new(iter.merge(class.iter()))), 
       } 
      }); 
      iter.unwrap() 
     }, 
     Class::Or(ref classes) => { 
      let iter: Option<_> = classes.iter().fold(None, |iter, &class| { 
       match iter { 
        None => Some(Box::new(class.iter())), 
        Some(iter) => Some(Box::new(iter.interleave(class.iter()))), 
       } 
      }); 
      iter.unwrap() 
     }, 
    } 
} 

Cela devrait fonctionner.