Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a non consuming iterator from a Vector

Tags:

rust

Situation:

I have a situation where I would like to call some method defined on the Iterator trait on a function parameter. The function that I would like to call it is taking a parameter of a type which is a trait called VecLike. The function is called get_all_matching_rules.

get_all_matching_rules can receive either a Vec or another similar home made type which also implements Iterator. Of course both of these implement VecLike. I was thinking of adding a function on VecLike to have it return an Iterator so that I could use it in get_all_matching_rules.

If my parameter is named: matching_rules I could then do matching_rules.iter().filter(.

Question:

How do I return a non consuming iterator from a Vec?

I'd like to be able to return a non consuming iterator on a Vec<T> of type Iterator<T>. I am not looking to iterate the items by calling .iter().

If I have (where self is a Vec):

fn iter<'a>(&'a self) -> Iterator<T> {
    self.iter()
}

I get the following error:

error: mismatched types: expected `core::iter::Iterator<T>+'a`, found `core::slice::Items<'_,T>` (expected trait core::iter::Iterator, found struct core::slice::Items)

I would like to return the Iterator<t>. If there is a better way to go at this rather than returning an Iterator, I'm all ears.

like image 945
Gilles Avatar asked Nov 16 '14 03:11

Gilles


1 Answers

.iter() on [T], which Vec<T> automatically dereferences to, takes self by reference and produces a type implementing Iterator<&T>. Note that the return type is not Iterator<&T>; Iterator is a trait which is implemented by concrete types, and the concrete type Items<T> is the return type in that case, not Iterator<&T>. There is not currently any syntax for specifying a return type merely as a trait that is implemented by it, though the syntax impl Iterator<&T> has been suggested.

Now you wish something implementing Iterator<T> rather than Iterator<&T>. Under Rust’s memory model where each object is owned by exactly one thing, this is not possible with the same objects; there must be some constraint to allow you to get a new T from the &T. There are two readily provided solutions for this:

  1. The Copy trait, for types that can just be copied bitwise. Given a variable of a type implementing Iterator<&T> where T is Copy, this can be written .map(|&x| x) or .map(|x| *x) (the two are equivalent).

  2. The Clone trait, for any types where the operation can be caused to make sense, regardless of Copy bounds. Given a variable of a type implementing Iterator<&T> where T is Clone, this can be written .map(|x| x.clone()).

Thus, given a vector v, v.iter().map(|x| x.clone()). Generically, something like this:

fn iter<T: Clone>(slice: &[T]) -> Map<&T, T, Items<T>> {
    slice.iter().map(|x| x.clone())
}
like image 161
Chris Morgan Avatar answered Sep 21 '22 06:09

Chris Morgan