1

I want to create a struct that accepts both a Vec<String> and a &[&str] (among other types):

pub struct Channel<I, T>
where
    I: IntoIterator<Item = T>,
    T: AsRef<str>,
{
    pub name: String,
    pub instruments: I,
}

When passing a Vec<String>, it works as expected:

pub struct Response {
    pub channels: Channel<Vec<String>, String>,
}

But when passing a &[&str]:

pub struct Request<'a> {
    pub channels: Channel<&'a [&'a str], &'a str>,
}

... I get the following error:

error[E0271]: type mismatch resolving `<&'a [&'a str] as IntoIterator>::Item == &'a str`
  --> src/lib.rs:11:19
   |
11 |     pub channels: Channel<&'a [&'a str], &'a str>,
   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `str`, found `&str`
   |
   = note: expected reference `&'a str`
              found reference `&&'a str`
note: required by a bound in `Channel`
  --> src/lib.rs:3:21
   |
1  | pub struct Channel<I, T>
   |            ------- required by a bound in this
2  | where
3  |     I: IntoIterator<Item = T>,
   |                     ^^^^^^^^ required by this bound in `Channel`

Why is T treated as a &&'a str in that case?

The solution is to use the following notation instead, but I really want to know why writing T as &'a str, which it actually is, does not work.

pub struct Request<'a> {
    pub channels: Channel<&'a [&'a str], &'a &'a str>,
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
guimauve
  • 408
  • 1
  • 5
  • 12
  • 1
    Why do you think that `&[T]` implements `Iterator`? (hint: it doesn't). – Shepmaster Apr 08 '22 at 19:11
  • 1
    Your question might be answered by the answers of [What is the difference between iter and into_iter?](https://stackoverflow.com/q/34733811/155423); [Difference between iter() and into_iter() on a shared, borrowed Vec?](https://stackoverflow.com/q/32234954/155423). If not, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Apr 08 '22 at 19:12
  • 1
    Have a look at the [implementation](https://doc.rust-lang.org/std/primitive.slice.html#impl-IntoIterator) of `IntoIterator` for `&'a [T]`. What is `T` in your code? – BallpointBen Apr 08 '22 at 19:15

1 Answers1

4

IntoIterator for &[T] yields references: &T, so since your slice type is &str, the iterator Item is &&str.

Also, your code can be simplified by not taking in the second generic parameter. You can use I::Item to constrain on the iterator type:

pub struct Channel<I>
where
    I: IntoIterator,
    I::Item: AsRef<str>,
{
    pub name: String,
    pub instruments: I,
}

let channels: Channel<Vec<String>>;
let channels: Channel<&[&str]>;
kmdreko
  • 42,554
  • 6
  • 57
  • 106