1

I have a Vec with iterators over slices. Some of them are in normal order, some are reversed.

 let mut output = Vec::new(); let input = b"1234567890"; let cuts = [(0,1), (1,3), (3, 5)]; for (start, end) in cuts{ output.push(input[start..end].iter()); output.push(input[start..end].iter().rev()); } 

But I can't compile it, because of

expected struct `std::slice::Iter`, found struct `Rev` 

I understand the error, but I wounder, if I can convert both iterators into some common type (without 'collecting' them).

UPD: I even tried to use .iter().rev().rev(), but it's a different type from iter().rev()...

2 Answers 2

5

An iterator and a reverse iterator are completely different types and cannot be stored in the same vector directly. They most likely aren't even the same size.

However, they both implement Iterator, of course. So you can store them via indirection, either as trait object references (&dyn Iterator) or as boxed trait objects (Box<dyn Iterator>). Which one depends on your usecase; the first one is with less overhead, but borrowed; the second one has a minimal overhead, but owns the objects.

In your case, as you don't keep the iterator objects around and instead want to store them in the list directly, the proper solution would be to use Box<dyn Iterator>, like this:

fn main() { let mut output: Vec<Box<dyn Iterator<Item = &u8>>> = Vec::new(); let input = b"1234567890"; let cuts = [(0, 1), (1, 3), (3, 5)]; for (start, end) in cuts { output.push(Box::new(input[start..end].iter())); output.push(Box::new(input[start..end].iter().rev())); } for iter in output { println!("{:?}", iter.collect::<Vec<_>>()); } } 
[49] [49] [50, 51] [51, 50] [52, 53] [53, 52] 

Minor nitpick:

Iterators over &u8 are discouraged, because &u8 are actually larger than u8. As u8 are Copy, adding copied() to the iterator reduces the item size without any cost; most likely even with a performance benefit.

Reason is that returning a &u8 is slower than a u8 (because &u8 is either 4 or 8 byte, while u8 is a single byte). Further, accessing a &u8 has one indirection, while accessing a u8 is very fast.

So I'd rewrite your code like this:

fn main() { let mut output: Vec<Box<dyn Iterator<Item = u8>>> = Vec::new(); let input = b"1234567890"; let cuts = [(0, 1), (1, 3), (3, 5)]; for (start, end) in cuts { output.push(Box::new(input[start..end].iter().copied())); output.push(Box::new(input[start..end].iter().copied().rev())); } for iter in output { println!("{:?}", iter.collect::<Vec<_>>()); } } 
[49] [49] [50, 51] [51, 50] [52, 53] [53, 52] 

Of course this is only true for &u8 and not for &mut u8; if you want to mutate the original items, copying them is counterproductive.

Sign up to request clarification or add additional context in comments.

4 Comments

I'm not completely understood reasoning for &u. I expected to work with &[u8], not &u8. Imagine I got 1GB of [u8]. I cut it in three peaces. Three &u is a little, but three big [u8] is 1GB in size.
No, you misunderstand. I don't want the iterators to own the vectors, they definitely should only reference the vectors. .copied() works on the fly, it means that the iterator returns a copy of each element instead of a reference to the element. As your elements are not mutable, it is much faster to have the iterator copy each of them out when iterating over them rather than returning references to each item.
Like, if you iterate over a &[u8], each produced element should be a u8. But because by default iter() is not allowed to copy the elements, it returns a &u8 that references the item in the original vector. This is only benefitial if you want to modify the original item; if you iterate over it immutably, this behaviour reduces performance. It's much faster if the iterator returns copies of the elements instead of references, for trivially-copyable types like u8.
@GeorgeShuklin Consider using Clippy. It points out little things like that, making it a great teaching tool.
4

To convert iterators into a common type you can use dynamic dispatch by storing trait objects into your output vector:

let mut output: Vec<Box<dyn Iterator<Item = _>>> = Vec::new(); let input = b"1234567890"; let cuts = [(0, 1), (1, 3), (3, 5)]; for (start, end) in cuts { output.push(Box::new(input[start..end].iter())); output.push(Box::new(input[start..end].iter().rev())); } 

Playground

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.