I have a function which returns an impl Stream
that I want to call from a method in another trait
. Here's a very rough example of what I'm trying to accomplish:
struct Example<S>
where
S: Stream<Item = String>,
{
phantom: std::marker::PhantomData<S>,
}
trait Thing<S> {
fn go(self) -> S;
}
impl<S> Thing<S> for Example<S>
where
S: Stream<Item = String>,
{
fn go(self) -> S {
the_stream()
}
}
fn the_stream() -> impl Stream<Item = String> {
stream::unfold(0, |i| async move { Some((i.to_string(), i + 1)) })
}
This produces the error:
expected type parameter
S
found opaque typeimpl Stream<Item = String>
The type parameter S
has the same constraints as the return type of the_stream
but the compiler is unable to match them up. I'm clearly missing some understanding of how opaque types can map to type parameters. Is there something I can do to help the compiler out and get the code running without boxing the stream?
While they both implement the same trait
the types S
and impl Stream<Item = String>
are in fact different types. With a generic type parameter the caller of the function can determine what concrete type they want. But with an opaque type parameter they can't specify that, all the user knows is that there exists some type that implements it.
Consider this example:
use std::collections::HashSet;
fn generic<A: FromIterator<u8>>() -> A {
(1..9).collect()
}
fn existential() -> impl FromIterator<u8> + std::fmt::Debug {
(1..9).collect::<Vec<_>>()
}
fn main() {
let v: Vec<_> = generic();
let s: HashSet<_> = generic();
dbg!(v, s);
let e = existential();
dbg!(e);
}
The function generic
can return any type that implements FromIterator<u8>
we want, the existential one always produces a Vec<u8>
but we can't even assume that, all we can use are the traits we specify namely FromIterator<u8>
which doesn't really let us do anything with the type. For demonstration purposes I also added the Debug
trait so we can inspect the output of existential
There is no way to define generic
in terms of existential
because existential can only ever return the same type while generic
has to produce the requested type.