I'd like to reuse an iterator I made, so as to avoid paying to recreate it from scratch. But iterators don't seem to be clone
able and collect
moves the iterator so I can't reuse it.
Here's more or less the equivalent of what I'm trying to do.
let my_iter = my_string.unwrap_or("A").chars().flat_map(|c|c.to_uppercase()).map(|c| Tag::from(c).unwrap() );
let my_struct = {
one: my_iter.collect(),
two: my_iter.map(|c|{(c,Vec::new())}).collect(),
three: my_iter.filter_map(|c|if c.predicate(){Some(c)}else{None}).collect(),
four: my_iter.map(|c|{(c,1.0/my_float)}).collect(),
five: my_iter.map(|c|(c,arg_time.unwrap_or(time::now()))).collect(),
//etc...
}
iterators are not reusable; you need to get a fresh Iterator from the Iterable collection each time you want to iterate over the elements.
In Rust, iterators are lazy, meaning they have no effect until you call methods that consume the iterator to use it up. For example, the code in Listing 13-10 creates an iterator over the items in the vector v1 by calling the iter method defined on Vec<T> . This code by itself doesn't do anything useful.
fn last(self) -> Option<Self::Item> Consumes the iterator, returning the last element. This method will evaluate the iterator until it returns None . While doing so, it keeps track of the current element. After None is returned, last() will then return the last element it saw.
collect() can take all the values in an Iterator 's stream and stick them into a Vec . And the map method is now generating Result<i32, &str> values, so everything lines up.
You should profile before you optimize something, otherwise you might end up making things both slower and more complex than they need to.
The iterators in your example
let my_iter = my_string.unwrap_or("A").chars().flat_map(|c|c.to_uppercase()).map(|c| Tag::from(c).unwrap() );
are thin structures allocated on the stack. Cloning them isn't going to be much cheaper than building them from scratch.
Constructing an iterator with .chars().flat_map(|c| c.to_uppercase())
takes only a single nanosecond when I benchmark it.
According to the same benchmark, wrapping iterator creation in a closure takes more time than simply building the iterator in-place.
Cloning a Vec
iterator is not much faster than building it in-place, both are practically instant.
test construction_only ... bench: 1 ns/iter (+/- 0)
test inplace_construction ... bench: 249 ns/iter (+/- 20)
test closure ... bench: 282 ns/iter (+/- 18)
test vec_inplace_iter ... bench: 0 ns/iter (+/- 0)
test vec_clone_iter ... bench: 0 ns/iter (+/- 0)
Iterators in general are Clone
-able if all their "pieces" are Clone
-able. You have a couple of them in my_iter
that are not: the anonymous closures (like the one in flat_map) and the ToUppercase struct returned by to_uppercase
.
What you can do is:
my_iter
into a Vec
before populating my_struct (since you seem to collect it anyway in there): let my_iter: Vec<char> = my_string.unwrap_or("A").chars().flat_map(|c|c.to_uppercase()).map(|c| Tag::from(c).unwrap() ).collect();
my_string
(since you call unwrap_or
on it I assume it's not a String
) and Tag
it's hard to help you more concretely with this.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With