Kapichu
Kapichu

Reputation: 3706

Take an `Iterator` instead of `Vec` when possible?

When a function takes a series of values as a parameter, is it considered good style to accept an Iterator<T> instead of Vec<T>?

This way, the caller can decide on their own how the series is stored (inside a Vec, a [T; N] or anything else, actually an Option<T> should be possible!). Also, this eliminates the need to convert the whatever you have into a Vec, and also, after applying some Iterator modifiers, no .collect() is needed! So it should also be faster!

Am I missing something or is this the way it should be done?

Upvotes: 11

Views: 262

Answers (1)

Chris Morgan
Chris Morgan

Reputation: 90712

Such a function as you describe should typically generically take an IntoIterator<Item = T>; thus it can accept both Iterator<T> and Vec<T> as input.

This can be combined with other techniques, too; for example, this method concat will accept a &[&str] (and thus &Vec<&str> by auto deref/ref coercion), &[String] (and thus &Vec<String>), a &str iterator, a String iterator, et cetera:

use std::borrow::Borrow;

fn concat<T: Borrow<str>, Iter: IntoIterator<Item = T>>(iter: Iter) -> String {
    iter.into_iter()  // -> impl Iterator<Item = T>
        .map(|s| s.borrow()) // -> impl Iterator<Item = &str>
        .collect()  // -> String
}

(This specific example would actually typically be better suited to Concat, because it’s able to calculate how long the final result will be up front and thus allocate the right length string all at once. But it’s just a proof of the concept and how multiple fancy techniques can be combined.)

Upvotes: 12

Related Questions