Associated Type with generic

Hi, I am trying to create a trait, which has a method that must return a struct which has a trait applied to it. I.e.

trait MyTrait {
    type Return: OtherTrait;

    fn method() -> Self::Return;
}

Now, when I come to applying this trait to a struct, the struct that I want to return has other generics, i.e.

struct OtherStruct<A, B, C> {
....
}

impl MyTrait for MyStruct {
    type Return = OtherStruct<A, B, C>;

    fn method() -> Self::Return {
        todo!()
    }
}

However, when I do this, I get an error and I cant seem to work out what is the correct syntax to define what A B and C are in the impl MyTrait for MyStruct.

Any help would be much appreciated.

Thanks
Karl

if MyStruct is not generic, you'll have to define the associated type to be a concrete type (non-generic), something like:

impl MyTrait for MyStruct {
    type Return = OtherStruct<bool, i32, ()>;
    //...
}

otherwise it's a compile error, the associated type cannot be decided. i.e. the following type alias must work:

type MyStructReturnType = <MyStruct as MyTrait>::Return;

you can only define generic parameters for impl if they are constrained by the type, e.g. suppose the MyStruct type has two generic parameters:

struct MyStruct<A, B> {
    //...
}

// you can NOT have more than one of the following impl blocks defined at
// the same time, if they don't have trait bounds to prevent conflicts

// introduced one generic type variable `A`
impl<A> MyTrait for MyStruct<A, isize> {
    // can use A or concrete types
    type Return = OtherStruct<A, B, isize>;
}
// introduce two generic type variables `A` and `B`
impl<A, B> MyTrait for MyStruct<A, B> {
    type Return = OtherStruct<A, isize, B>;
}

however, unconstrained generic type is compile error:

// error[E0207]: the type parameter `C` is not constrained by the impl trait, self type, or predicates
impl<A, B, C> MyTrait for MyStruct<A, B> {
    type Return = OtherStruct<A, B, C>;
}

Thanks @nerditation!

So to be able to have type Algorithm = OtherStruct<A, B, C>, would I need to have MyStruct to have 3 generics: A, B, C? I read something about PhantomData and how that might be useful in this case, but still unsure about this.

no, not necessarily, you can use concrete types for OtherStruct, depending what you want it to be. it's MyStruct determines the associated Return type, not the Return type determines MyStruct. the fact OtherStruct is generic doesn't mean everytime you use it, you must in a generic context.

example:

trait Trait {
    type Associated;
}

// this type isn't generic, it's just deal with i32
struct NotGeneric {}
impl Trait for NotGeneric {
    type Associated = Vec<i32>;
}


// this type is generic, it deals with any type T
struct Generic<T>(PhantomData<T>);

// but we can implements Trait for a concrete type
impl Trait for Generic<i32> {
    type Associated = Vec<bool>;
}

// we can also implement the trait generically
impl<T: Iterator> Trait for Generic<T> {
    type Associated = Vec<T::Item>;
}


EDIT:

in this example, Vec<T, A: Allocator = Global> is a generic type, it has 2 generic type parameters T and A (similar to how OtherStruct<A, B, C> has 3 generic parameters), but it doesn't mean you have to use Vec<T> with a generic type T all the time. you can just use concrete types like Vec<i32>, Vec<bool>, etc if you are not in a generic context.

1 Like

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.