Pre-RFC: Iterator::extend


#1

I’ve got an idea about improving Iterator. Since it came into my head I started noticing more and more places, where I wished I could use this. I didn’t find any trace of anybody proposed it yet, so I’m giving it a shot. What do you think?

Summary

Add Iterator::extend method, which takes a collection and extend it with iterator’s self.

Motivation

Sometimes there is a need to create a sophisticated iterator and then put all it’s items into a collection. Of cource there is Iterator::collect, which creates a new collection, but there is no convenient method of collecting into an EXISTING one.

Sure, it’s possible, but a bit awkward:

fn my_fn(&self, vec: &mut Vec) {
    let iter = self.items.iter()
        .filter(...)
        .enumerate()
        .map(...);
    vec.extend(iter);
}

or more compact, but way harder to follow:

fn my_fn(&self, vec: &mut Vec) {
    vec.extend(self.items.iter()
        .filter(...)
        .enumerate()
        .map(...)
    );
}

but nothing beats THIS:

fn my_fn(&self, vec: &mut Vec) {
    self.items.iter()
        .filter(...)
        .enumerate()
        .map(...);
        .extend(vec);
}

extend could return the extended collection:

fn my_fn(&self, vec: &mut Vec) -> usize {
    self.items.iter()
        .filter(...)
        .enumerate()
        .map(...);
        .extend(vec)
        .len()
}

Implementation

No rocket science here.

pub trait Iterator {
    type Item;

    ...

    fn extend<B, E>(self, extended: B) -> B
    where
        B: BorrowMut<E>,
        E: Extend<Self::Item> {
        extended.borrow_mut().extend(self);
        extended
     }
}

The Borrow allows passing collections either by value or by reference, which makes it much more elastic.


#2

It sounds like a good idea to me! You might even use this in places where collect() is used now, if you can predict the capacity better than size_hint() reports, or if you want to reuse an existing allocation. (Both of which are already possible with Extend though.)

One place where this might fall down is if a type implements Iterator and Extend already, then calling extend() may be ambiguous. I don’t think that’s going to be common, but Either does (conditionally) implement both. (cc @bluss)


#3

Good point about naming, it should be something new, like extend_into.


#4

Related:


#5

It is better to create this in internals.


#6

Since the subject/object roles of self and arg are switched here compared to Vec, I’d suggest a different name (e.g., extend_into).


#7

Thank you, @scottmcm, I’ve added my 5 cents there :slight_smile:

Thank you, @dylan.dpc, I’ve created post there as well: https://internals.rust-lang.org/t/pre-rfc-iterator-extend-into/6662