6

In the following Rust snippet:

fn main() { let list1: Vec<i32> = vec![0, 1, 2, 3, 4]; let it1 = list1.iter(); let tens = it1.map(|x| x * 10).collect::<Vec<i32>>(); println!("{:?}", tens); let it2 = list1.iter(); let doubled_from_iter = scale_it_iter(&it2); println!("{:?}", doubled_from_iter); } fn scale_it_iter(l: &dyn Iterator<Item = &i32>) -> Vec<i32> { l.map(|x| x * 2).collect() } 

Rust Playground Link

I get this error:

error: the `map` method cannot be invoked on a trait object --> src/main.rs:15:7 | 15 | l.map(|x| x * 2).collect() | ^^^ | ::: /home/xolve/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:625:15 | 625 | Self: Sized, | ----- this has a `Sized` requirement | = note: you need `&mut dyn Iterator<Item = &i32>` instead of `&dyn Iterator<Item = &i32>` error: aborting due to previous error 

Adding mut as suggested by the compiler solves this. Rust Playground link for working code.

I do not understand why it is needed. It's not needed in main when I call it1.map.

I don't understand the error messages.

  1. the `map` method cannot be invoked on a trait object is solved by adding mut to the trait reference. This seems contradictory.
  2. How is the message about the Sized trait bound related to the error?
1
  • Iterator::map mutates the iterator, so you need a mutable reference. Commented Jan 16, 2021 at 20:08

1 Answer 1

5

The "map method cannot be invoked on a trait object" and "this has a Sized requirement" error messages are because map() consumes the original iterator. dyn Traits cannot be consumed (they are unsized types and cannot be passed to functions by value).

It works for it1 because 1) its not a trait object, its a concrete type Iter and 2) its not a reference so it is consumed.

The reason that &mut dyn Iterator works is because &mut dyn Iterator implements Iterator. The effective difference is just the reference is consumed and the underlying iterator is mutated.


If you want to follow convention, I'd make scale_it_iter consume the iterator like so:

fn scale_it_iter<'a>(l: impl Iterator<Item = &'a i32>) -> Vec<i32> { l.map(|x| x * 2).collect() } 
Sign up to request clarification or add additional context in comments.

2 Comments

Even better regarding convention, the function could accept impl IntoIterator and use l.into_iter()..... That way one can pass it not just iterators, but also collections or other iterables.
@kmdreko In snippet with impl Iterator I do not need to add mut to iterator. The map method still mutates the iterator though.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.