Hi!
I'm wondering if it's possible in rust to have a function return some implementation of a trait that uses associated types in general.
Here's an example set up:
fn main() {
use std::marker::PhantomData;
trait ATrait {}
impl ATrait for usize{}
trait BTrait<T, L> where T: Into<usize>, L: ATrait {}
struct BImpl<T, L> {
phantom1: PhantomData<T>,
phantom2: PhantomData<L>,
}
impl<T, L> BTrait<T, L> for BImpl<T, L> where T: Into<usize>, L: ATrait {}
trait MyTrait {
type A: ATrait;
type B: BTrait<usize, Self::A>;
}
struct Impl1{}
impl MyTrait for Impl1 {
type A = usize;
type B = BImpl<usize, usize>;
}
struct Impl2{}
impl MyTrait for Impl2 {
type A = usize;
type B = BImpl<usize, usize>;
}
}
The goal here would be to have a function say new_mytrait
that returns an arbitrary implementation of MyTrait
to the caller - so sometimes Impl1
sometimes Impl2
.
Ideally this would be something like:
// A function that explicitly returns e.g a boxed object is also welcome.
fn new_mytrait<M: MyTrait>() -> M {
if true {
Impl1{}
} else {
Impl2{}
}
}
let m = new_mytrait();
- Is such a function possible in rust? What does it look like?
Somethings I noticed about this:
- Rust really really wants you to spell out values for all the associated types in traits that have them. As an example:
trait Foo {
type A;
}
struct Bar {}
impl Foo for Bar {
type A = usize;
}
let b: Box<dyn Foo> = Box::new(Bar{}); // Does not compile
let b: Box<dyn Foo<_>> = Box::new(Bar{}); // Does not compile
let b: Box<dyn Foo<A=usize>> = Box::new(Bar{}); // OK
Its not clear to me besides compiler limitations, why the compiler doesn't infer the type of b
- its clear from the trait implementation for Bar
?
The issue here is that in a trait with multiple associated types, each in turn traits with associated types and so on, it won't be practical to spell out the type explicitly.
- But back to another issue with the
MyTrait
example is that rust says it doesn't know how to create a trait object for it to begin with, because the trait self-references its associated types.
|
14 | trait MyTrait {
| ------- this trait cannot be made into an object...
15 | type A: ATrait;
16 | type B: BTrait<usize, Self::A>;
| ---------------------- ...because it uses `Self` as a type parameter in this
...
31 | let b: Box<dyn MyTrait<A= usize, B= BImpl<usize, usize>>> = Box::new(Impl1{});
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `main::MyTrait` cannot be made into an object
Are these compiler quirks or maybe I'm missing something with these behaviors?