Here is the working version:
struct Primes<'a> { base: Option<Box<Iterator<Item=u64>+'a>>, } impl<'a> Iterator for Primes<'a> { type Item = u64; fn next(&mut self) -> Option<u64> { let p = self.base.as_mut().unwrap().next(); p.map(|n| { let base = self.base.take(); let step = base.unwrap().filter(move |x| x % n != 0); self.base = Some(Box::new(step)); n }) } } impl<'a> Primes<'a> { #[inline] pub fn new<I: Iterator<Item=u64>+'a>(r: I) -> Primes<'a> { Primes { base: Some(Box::new(r)) } } } fn main() { for p in Primes::new(2..).take(32) { print!("{} ", p); } println!(""); }
First, I use the trait Box<Iterator> object. Boxing is inevitable, because the internal iterator must be stored somewhere between calls to next() , and with objects of reference objects there is nowhere to save it.
Secondly, I made an internal Option iterator. This is necessary because you need to replace it with a value that consumes it, so it is possible that the internal iterator may be "out" of the structure for a short time. Lack of rust patterns with Option . take() method on Option replaces the value by which it is called using None , and returns everything that was there. This is useful when shuffling non-copied objects.
Please note, however, that this implementation of the sieve will be both memory and computationally inefficient - for each step you create an additional layer of iterators that takes up a lot of space. Also, the stack depth when calling next() grows linearly with the number of primes, so you get a stack overflow on a fairly large number:
fn main() { println!("{}", Primes::new(2..).nth(10000).unwrap()); }
Launch:
% ./test1 thread '<main>' has overflowed its stack zsh: illegal hardware instruction (core dumped) ./test1
source share