Although in this example it is just a matter of "style preference", the problem does indeed arrive when unnameable types are involved: let's image someone wants to have:
struct Session<F : Fn()> {
f: F,
}
impl Session<?> {
fn new () -> Session<impl Fn()>
{
Session { f: || println!("Demo"), }
}
}
-
your code example is similar to this situation, except that you could name the type but you don't want to, to ease refactoring.
-
I already covered this use case in an old post: Embedding Trait inside of Struct - #14 by Yandros
In that case, the clean solution would be to use existential types:
type WebSocketStream = impl Stream...;
// attach the actual type with a constructor:
fn mk_websocket_stream (...) -> WebSocketStream
{
connect_secure(...)
/* could be refactored as
connect_insecure(...) // */
}
/// And now we can do:
struct Session { // <- no longer generic!
client: WebSocketStream.
}
impl Session {
fn new (...) -> Self
{
Self { client: mk_websocket_stream(...) }
}
}
Now, on stable we don't have this, so we need to be a bit more hacky creative :
The idea will be to have Session::new()
return a Session<impl Stream>
, although this return type cannot be Self
, since there is no way to impl for ...<impl Stream>
on stable Rust.
This isn't a problem, as long as we don't introduce an unused generic type parameter.
So, for instance, we can do:
pub
struct Session<T> { // <- no trait bound **yet**
client: T,
}
impl Session</* what do we put here? */> {
pub
fn new (...) -> Session<impl Stream>
{
let client = ...;
Self { client }
}
}
/// CLASSIC IMPLS HERE:
// generic impl just to be able to cover the above `impl Stream` unnameable type.
impl<T : Stream> Session<T> {
...
}
So, the only question remaining is:
what type do we use in
/* what do we put here */
?
And the answer is: whatever you want, as long as it is not generic:
/// Even a type as dumb as `()` works.
impl Session<()> {
fn new (...) -> Session<impl Stream> { ... }
}
/// Using `dyn Trait` for something that becomes `impl Trait` may "read / look better"
impl Session<dyn Stream> { // <- But you need to be able to use a `?Sized` type param
...
}
// The longer but better looking solution
use private::impl_Stream;
mod private {
#![allow(nonstandard_style)]
pub
struct impl_Stream;
/// If you have added a `: Stream` boubnd even at the struct definition
/// you will need a dummy impl of Stream for this dummy type;
impl Stream for impl_Stream { ... unreachable!() ... unreachable!() ... }
}
/// so that you can do:
impl Session<impl_Stream> {
fn new (...) -> Stream<impl Stream> { ... }
}