Search code examples
rustiterator

Implement iterator that does not consume


I have this code, for learning purposes:

struct Fibonacci {
    curr: u32,
    next: u32,
}

impl Iterator for Fibonacci {
    type Item = u32;

    fn next(&mut self) -> Option<Self::Item> {
        let current = self.curr;

        self.curr = self.next;
        self.next = current + self.next;
        Some(current)
    }
}

impl Fibonacci {
    fn new() -> Self {
        Fibonacci { curr: 0, next: 1 }
    }

    fn current(&self) -> u32 {
        self.curr
    }
}

fn main() {
    println!("The first four terms of the Fibonacci sequence are: ");
    let fib = Fibonacci::new();
    for i in fib.take(4) {
        println!("> {}", i);
    }
    // println!("cur {}", fib.current()); // *fails*
   
}

Here fib.take(4) consumes the fib value, so the commented out println below the loop doing fib.current() fails , quite naturally, with:

    let fib = Fibonacci::new();
         --- move occurs because `fib` has type `Fibonacci`, which does not implement the `Copy` trait
    for i in fib.take(4) {
                  ------- `fib` moved due to this method call
...
     println!("cur {}", fib.current());
                        ^^^^^^^^^^^^^ value borrowed here after move

note: this function takes ownership of the receiver `self`, which moves `fib`

How would I implement the code above such that the Iterator does not consume it's value, and I can use the fib variable after the loop ?


Solution

  • You can use .by_ref():

    Borrows an iterator, rather than consuming it.

    This is useful to allow applying iterator adapters while still retaining ownership of the original iterator.

    println!("The first four terms of the Fibonacci sequence are: ");
    let mut fib = Fibonacci::new();
    for i in fib.by_ref().take(4) {
        println!("> {}", i);
    }
    println!("cur {}", fib.current());
    
    The first four terms of the Fibonacci sequence are: 
    > 0
    > 1
    > 1
    > 2
    cur 3