Extension traits

Един недостатък на нашите имплементации на адаптери за итератори (от упражнение 07), е че не са методи и не можем да ги навържем един след друг с method chaining.

// std
iter
    .filter(|x| some_condition(x))
    .map(|x| something(x));

// нашият код
let iter = my_filter(iter, |x| some_condition(x));
let iter = my_map(iter, |x| something(x));
iter

В такива случаи можем да си направим extension trait.
Trait-а IteratorExt:

  • може да се имплементира само върху итератори, защото има trait bound IteratorExt: Iterator
  • е имплементиран върху всички итератори, поради blanket impl блока на края

Например това се използва от пакета https://docs.rs/itertools/ за да добави още повече методи към итераторите.

trait IteratorExt: Iterator {
    fn my_map<F, U>(self, func: F) -> Map<Self, F>
    where
        F: Fn(Self::Item) -> U,
        Self: Sized,
    {
        iter_map(self, func)
    }

    fn my_filter<F>(self, func: F) -> Filter<Self, F>
    where
        F: Fn(&Self::Item) -> bool,
        Self: Sized,
    {
        iter_filter(self, func)
    }
}

impl<I> IteratorExt for I where I: Iterator {}

Това ни позволява да пишем

iter
    .my_filter(|x| some_condition(x))
    .my_map(|x| something(x))