Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 747
Kapichu Avatar asked Jul 15 '15 22:07

Kapichu


1 Answers

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 SliceConcatExt, 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.)

like image 86
Chris Morgan Avatar answered Nov 01 '22 02:11

Chris Morgan