Home > database >  Is there a way to define type alias in generic struct impl block in Rust?
Is there a way to define type alias in generic struct impl block in Rust?

Time:10-02

I have a generic struct with a lot of type parameters:

struct J<A, B, C, D, E, F, G>{...}

as well as other structs that use subsets of those parameters:

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

struct I<C, D, E, F, G>{...}

I am writing methods for J which will often use H or I with the same type parameters:

impl<A, B, C, D, E, F,G> J<A, B, C, D, E, F,G> {
    fn f_1() -> I<C, D, E, F, G> {...}
    fn f_2() -> H<A, B, C> {...}
}

Now re-writing the type parameters so much is very cumbersome, so it only makes sense to be able to do something like:

impl<A, B, C, D, E, F,G> J<A, B, C, D, E, F,G> {
    type MyI = I<C, D, E, F, G>;
    type MyH = H<A, B, C>;

    fn f_1() -> MyI {...}
    fn f_2() -> MyH {...}
}

Like you would be able to with associated types in a trait. I haven't found any way of expressing this though that the Rust compiler is happy with. The above errors with:

error[E0658]: inherent associated types are unstable
  --> src/lib.rs:14:5
   |
14 |     type MyI = I<C, D, E, F, G>;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: see issue #8995 <https://github.com/rust-lang/rust/issues/8995> for more information

error[E0658]: inherent associated types are unstable
  --> src/lib.rs:15:5
   |
15 |     type MyH = H<A, B, C>;
   |     ^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: see issue #8995 <https://github.com/rust-lang/rust/issues/8995> for more information

error[E0223]: ambiguous associated type
  --> src/lib.rs:17:17
   |
17 |     fn f_1() -> Self::MyI {
   |                 ^^^^^^^^^ help: use fully-qualified syntax: `<J<A, B, C, D, E, F, G> as Trait>::MyI`

error[E0223]: ambiguous associated type
  --> src/lib.rs:20:17
   |
20 |     fn f_2() -> Self::MyH {
   |                 ^^^^^^^^^ help: use fully-qualified syntax: `<J<A, B, C, D, E, F, G> as Trait>::MyH`

Is there really no way to do it?

CodePudding user response:

As the compiler error suggests, this functionality is currently not supported. The tracking issue is https://github.com/rust-lang/rust/issues/8995.

As a work-around, you can define a separate trait MyTypes implemented by J that has the necessary associated types. However, the syntax for accessing them (<Self as MyTypes>::MyI) isn't much less verbose. An advantage of this approach is that if you ever need to change MyI, you will only need to do so in a single place.

trait MyTypes {
    type MyI;
    type MyH;
}

impl<A, B, C, D, E, F, G> MyTypes for J<A, B, C, D, E, F, G> {
    type MyI = I<C, D, E, F, G>;
    type MyH = H<A, B, C>;
}

impl<A, B, C, D, E, F, G> J<A, B, C, D, E, F, G> {
    fn f_1() -> <Self as MyTypes>::MyI { todo!() }
    fn f_2() -> <Self as MyTypes>::MyH { todo!() }
}

playground

  • Related