This trait has several issues, but no one of them is connected to using Self::Out
as parameter. Let's go through it:
- Compiler says that you can't use the trait in this case without specifying its associated type, i.e. in function
subscribe
you must accept something like Layer<Self::Out, Out = Next>
. So the trait will look like this:
trait Layer<In> {
type Out;
fn map(i: In) -> Self::Out;
fn subscribe<Next>(l: Layer<Self::Out, Out = Next>);
}
- The compiler, however, is not happy again:
error[E0038]: the trait `Layer` cannot be made into an object
--> src/lib.rs:4:5
|
4 | fn subscribe<Next>(l: Layer<Self::Out, Out = Next>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Layer` cannot be made into an object
|
= note: method `map` has no receiver
= note: method `subscribe` has no receiver
This means that you've used the deprecated trait object syntax.
Instead, you probably want to make subscribe
function generic, i.e. have it compiled for every incoming layout as necessary. This is granted by a small change in singature:
trait Layer<In> {
type Out;
fn map(i: In) -> Self::Out;
fn subscribe(l: impl Layer<Self::Out>);
}
Note the impl
and the fact that the Next
type is now unnecessary. More explicit way would be to write this:
fn subscribe<Arg: Layer<Self::Out>>(l: Arg);
i.e. add the generic parameter with trait bound, but semantically these two are equivalent.
- For now, it's unclear how this trait should be used. Look again at the previous error:
= note: method `map` has no receiver
= note: method `subscribe` has no receiver
This means that the trait is, essentially, a collection of functions, not attached to any object - only to the type. If this is OK, well, we've finished, but if you want to use them as object methods - you must add the receivers - argument referencing the object itself. This should possibly look like this:
trait Layer<In> {
type Out;
fn map(&self, i: In) -> Self::Out;
fn subscribe(&mut self, l: impl Layer<Self::Out>);
}
I'm not sure if subscribe
must really take the unique reference, or you'll go with some internal mutability, but in general - that's the way.
- The last but not the least. If you don't like the idea of multiple compiled instances of
subscribe
function for every input type, well, now - as we've added the receivers - we can go for dynamic dispatch, as you were trying at the start. But, instead of using deprecated syntax, we'll make the dynamic dispatch explicit by using the keyword dyn
:
trait Layer<In> {
type Out;
fn map(&self, i: In) -> Self::Out;
fn subscribe<Next>(&mut self, l: dyn Layer<Self::Out, Out = Next>);
}
Note, however, that we have to add the Next
generic type again, so maybe this way won't give you any profit over statically dispatched one.