2017-01-17 8 views
1

У меня есть код, который пытается выполнить совпадение, где каждая ветка может возвращать другой тип, но все эти типы реализуют Iterator<Item=usize>.Сопровождать оружие, возвращающее итераторы?

let found: Iterator<Item = usize> = match requirements { 
    Requirements::A => MatchingAs { ainternals: [] }, 
    Requirements::B => MatchingBs { binternals: [] }, 
    Requirements::C => MatchingCs { cinternals: [] }, 
}; 

return found.any(|m| m == 1) 

... где MatchingAs, MatchingBs и MatchingCs все implstd::iter::Iterator<Item = usize>.

Я ударяя стену с тем, что Iterator не SIZED:

| the trait `std::marker::Sized` is not implemented for `std::iter::Iterator<Item=usize>` 

Есть хороший подход, чтобы иметь спички руки возвращают объекты с общей чертой, а затем полагаться (только) по признаку обработки результатов?

+1

Пожалуйста, объясните, почему это не дубликат [Правильный способ возврата Итератора?] (Http://stackoverflow.com/q/27535289/155423) – Shepmaster

ответ

4

Первый рефлекс, когда вы хотите, чтобы вернуть то, что не Sized, является Box она (он же, поставить его в куче, возвращает указатель):

let found: Box<Iterator<Item = usize>> = match requirements { 
    Requirements::A => Box::new(MatchingAs { ainternals: [] }), 
    Requirements::B => Box::new(MatchingBs { binternals: [] }), 
    Requirements::C => Box::new(MatchingCs { cinternals: [] }), 
}; 

found.any(|m| m == 1) 

Этого недостаточно, здесь, потому что теперь match будет жаловаться, что вы возвращаете различные типы: Box<MatchingAs>, Box<MatchingBs> ...

Однако Box<Concrete> может быть приведен к Box<Trait> всякий раз, когда есть impl Trait for Concrete, так:

let found = match requirements { 
    Requirements::A => Box::new(MatchingAs { ainternals: [] }) as Box<Iterator<Item = usize>>, 
    Requirements::B => Box::new(MatchingBs { binternals: [] }) as Box<Iterator<Item = usize>>, 
    Requirements::C => Box::new(MatchingCs { cinternals: [] }) as Box<Iterator<Item = usize>>, 
}; 

found.any(|m| m == 1) 

Существует, однако, выделение менее решение: использование генериков.

fn search<T: Iterator<Item = usize>>(t: T) -> bool { 
    t.any(|m| m == 1) 
} 

, а затем применить эту функцию к каждой ветви match:

match requirements { 
    Requirements::A => search(MatchingAs {ainternals: []}), 
    Requirements::B => search(MatchingBs {binternals: []}), 
    Requirements::C => search(MatchingCs {cinternals: []}), 
} 

Компромисс в том, что это немного ближе к перезвонить-ад, с несколько непрямого потока.