CodeBlanks Logo Icon CodeBlanks

Iterator adapter

Write your own type that implements Iterator.

Final task: iterator adapter

Write your own iterator adapter: CiftAdim, which yields the elements of any iterator skipping every other one. The adapter wraps the inner iterator and, in next, pulls two elements from it and returns the first:

struct CiftAdim<I> {
    ic: I,
}

impl<I: Iterator> Iterator for CiftAdim<I> {
    type Item = I::Item;
    fn next(&mut self) -> Option<I::Item> {
        let x = self.ic.next();
        self.ic.next();     // skip one
        x
    }
}

Extension trait

To chain it as .cift_adim(), an extension trait is written and implemented generically for all iterators:

trait CiftAdimExt: Iterator + Sized {
    fn cift_adim(self) -> CiftAdim<Self> {
        CiftAdim { ic: self }
    }
}

impl<I: Iterator> CiftAdimExt for I {}

let v: Vec<i32> = (1..=7).cift_adim().collect();   // [1, 3, 5, 7]

The standard library's step_by(2) does the same job; this task shows how adapters are built.

Practice Your own adapter

Write the CiftAdim structure above, its Iterator implementation and the CiftAdimExt extension trait. Collect (1..=7).cift_adim() into a vector and "abcdef".chars().cift_adim() into a String, and print them separated by a space.

Starter code

main.rs
fn main() {
    // buraya yaz
}

Sample solution

main.rs
struct CiftAdim<I> {
    ic: I,
}

impl<I: Iterator> Iterator for CiftAdim<I> {
    type Item = I::Item;
    fn next(&mut self) -> Option<I::Item> {
        let x = self.ic.next();
        self.ic.next();
        x
    }
}

trait CiftAdimExt: Iterator + Sized {
    fn cift_adim(self) -> CiftAdim<Self> {
        CiftAdim { ic: self }
    }
}

impl<I: Iterator> CiftAdimExt for I {}

fn main() {
    let v: Vec<i32> = (1..=7).cift_adim().collect();
    let s: String = "abcdef".chars().cift_adim().collect();
    println!("{:?} {}", v, s);
}

Expected output

[1, 3, 5, 7] ace

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 What does <code>type Item = I::Item;</code> mean?

  • Item is always i32
  • I is an element type
  • It doesn't compile
  • The adapter produces elements of the same type as the inner iterator Correct answer

Explanation: I::Item is the associated type in I's Iterator implementation; the adapter passes it through unchanged.

2 Blanket implementation

Question
impl<I: ____> CiftAdimExt for I {}
Answer
impl<I: Iterator> CiftAdimExt for I {}

Explanation: All iterators gain the extension trait.

3 Input and cift_adim result

Term Meaning
1..=7 [1, 3, 5, 7]
"abcdef".chars() "ace"
1..=2 [1]
empty iterator []

All lessons in Intermediate