How to use the outer type for a generic type parameter in trait impls

Viewed 358

I have a minimal example as below.

There are two traits, TraitA and TraitB. TraitB has a generic function that uses TraitA as type parameter. TraitB has to be object safe so I mark the function with where Self: Sized. It works fine so far.

If I have a struct MyStruct<A: TraitA>, and I want to implement TraitB for it. The impl block will have impl<A: TraitA> TraitB for MyStruct<A>. But for the generic_func, the compiler complains that A is already used. I could not get the code to compile as I could not figure out what to put in the place of '???' in the example.

use std::marker::PhantomData;

// One trait
trait TraitA {}

// The other trait that has one generic function that uses TraitA
trait TraitB {
    fn generic_func<A: TraitA>(self) where Self: Sized;
}

// TraitB needs to be object safe
fn foo(a: &dyn TraitB) {
    
}

// The generic struct that uses TraitA, but needs to implement TraitB as well.
struct MyStruct<A: TraitA>(PhantomData<A>);

impl<A: TraitA> TraitB for MyStruct<A> {
    // What should I put as ???. It should refer to A.
    fn generic_func<???>(self) where Self: Sized {
    }
}

Rust playground link: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=4eff9e5a6fded93e03a090890f84e983

1 Answers

Any letter will do. C, D, Potato, etc., Rust doesn't care whether the generic variables have the same name, just that they're used in the same way (i.e. whatever you name it needs to be : TraitA)

impl<A: TraitA> TraitB for MyStruct<A> {
  fn generic_func<Potato: TraitA>(self) where Self: Sized {
  }
}

As you've written it, TraitB demands a generic_func that works for every type which implements TraitA. If you want it to work for a specific one, you need to write your trait differently.

trait TraitB {
  type MyA: TraitA;
  fn generic_func(self);
}

impl<A: Trait> TraitB for MyStruct<A> {
  type MyA = A;
  fn generic_func(self) { ... }
}

Now, inside of the trait, Self::MyA refers to the specific type which you're implementing this trait to work with.

Related