Pasing slice as IntoIterator

Hello everyone!

I'm struggling to make the Rust type system happy in this case, please help me.

I have a function that takes an IntoIterator argument:

fn show<T>(iterable: T)
    where T: IntoIterator<Item = i32> {
    todo!()
}

Then I have another function that takes a slice argument and I want to pass one into the other, like this:

fn adapt(elements: &[i32]) {
    show(elements);
}

This fails to compile with the following error:

 error[E0271]: type mismatch resolving `<&[i32] as IntoIterator>::Item == i32`
 --> src/main.rs:7:10
  |
7 |     show(elements);
  |     ---- ^^^^^^^^ expected `i32`, found `&i32`
  |     |
  |     required by a bound introduced by this call
  |
note: required by a bound in `show`
 --> src/main.rs:2:27
  |
1 | fn show<T>(iterable: T)
  |    ---- required by a bound in this function
2 |     where T: IntoIterator<Item = i32> {
  |                           ^^^^^^^^^^ required by this bound in `show`

So I understand that I'm passing an IntoIterator<Item = &i32> while this is expecting an IntoIterator<Item = i32>, but how to do the conversion?

When calling the show function directly, I can make something like this and it works fine:

show(*&[1, 2, 3]);

However, I can't do the same trick in the adapt function like this:

fn adapt(elements: &[i32]) {
    show(*elements);
}

Because I get the following error:

error[E0277]: `[i32]` is not an iterator
 --> src/main.rs:7:10
  |
7 |     show(*elements);
  |     ---- ^^^^^^^^^ the trait `IntoIterator` is not implemented for `[i32]`
  |     |
  |     required by a bound introduced by this call

The only workaround that I have found so far is to convert elements to a Vec, but I'm afraid this creates unnecessary allocations:

fn adapt(elements: &[i32]) {
    show(elements.to_vec());
}

How can I make this work?

You're passing an array that gets copied there ([i32; 3], not a slice ([i32]). You can't pass a slice that's not behind a reference or other pointer, because slices don't have a known size at compile time (they are "unsized", "dynamically sized", "DSTs").

Use an iterator adapter that copies the items:

fn adapt(elements: &[i32]) {
    show(elements.into_iter().copied());
}

(Note that every I: Iterator implements IntoIterator by returning itself.)

4 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.