2015-07-22 2 views
4

Мне нужно реализовать метод iter, который возвращает что-то, что реализует черту Iterator<Item = char>. Но возвращаемое значение будет отличаться от реализации, в зависимости от варианта перечисления.Как реализовать метод iter с помощью статической/динамической отправки?

Что-то вроде этого:

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() возвращает структуру, которая реализует Iterator<Item=char>.

merge и interleave являются itertools методы, которые возвращают MergeAscend и Interleave соответственно (оба реализации Iterator<Item=char>)

  1. Как реализовать такую ​​схему статической отправки?
  2. Если статическая отправка невозможна, как реализовать такую ​​схему с помощью динамической отправки?

ответ

3

Невозможно сделать это, используя статическую отправку. Существует tracking RFC issue на unboxed абстрактных типах возврата, но Rust еще не существует (и я не уверен, может ли он покрыть прецедент возврата различных типов). Поэтому динамическая отправка - это путь.

Вы на самом деле довольно близки. Просто сделайте тип возвращаемого Box<Iterator<Item=char>> и добавить больше бокса:

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() 
     }, 
    } 
} 

Это должно работать.

Смежные вопросы