Hi.
I have two traits A
and B<T>
, and struct C
. C
implements B<SomeType>
and dyn B<T>
implements A
.
I can use method of A
by (&c as &dyn B<SomeType>).method()
, but are there any other way?
That's the only way. &C
can be converted to &dyn B<T>
just like i32
can be converted to i64
.
No, the compiler needs to know what trait object type you're using. C
could implement B<SomeType>
and B<AnotherType>
, and then c.method()
would be ambiguous.
Possible alternatives might include making T
an associated type like E
is, adding a type parameter to C
, adding a type parameter to A
, or writing a new trait with a type parameter and a blanket impl
for U: B<T>
. That last one sounds complicated so here's what I mean:
trait Hello<T> {
type Err;
fn hello(&self);
}
impl<T, U: 'static + b::B<T>> Hello<T> for U {
type Err = U::E;
fn hello(&self) {
a::A::hello(self as &dyn b::B<T, E = Self::Err>);
}
}
fn main() {
let c = c::C {};
c.hello(); // the compiler can figure out `T` at this point
}
(Note that this relies on there being only one B<?>
implemented for C
; if you add another B
implementation, you'll have to specify which one by writing something like <C as Hello<u8>>::hello(&c)
.)
For a situation like this, Iād provide an as_a()
method on B
, and also (more optionally) a struct that can use static dispatch instead of dynamic:
mod b {
pub trait B<T> {
type E;
fn as_a(&'_ self) -> AsA<'_, T, Self> {
AsA {
val: self,
param: std::marker::PhantomData,
}
}
}
pub struct AsA<'a, T, Inner: 'a + ?Sized> {
val: &'a Inner,
param: std::marker::PhantomData<T>,
}
impl<'a, T, Inner: B<T> + 'a + ?Sized> crate::a::A for AsA<'a, T, Inner> {}
}
fn main() {
let c = c::C {};
c.as_a().hello();
}
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.