Search code examples
genericsrusttraitsbounds

Forcing two generics to be the same in impl


I have a Hittable trait, with a method that returns a generic implementing Material:

pub trait Hittable {
    fn hit<T>(&self -> Option<HitRecord<T>>
    where T: Material;
}

And an implementation of this trait on a Sphere<T>:

impl<T> Hittable for Sphere<T>
where T: Material
{
    fn hit(&self) -> Option<HitRecord<T>> {
        // snip
    }

I want the T in HitRecords to be the same as the T in Sphere<T>, but as of now now it will not compile because I need to annotate the hit method in the impl with a T as well. But if I do so, the 2 T's will not be forced to be the same. How do I enforce that?


Solution

  • You should uplift the generic parameter from the method into the trait:

    pub trait Hittable<T: Material> {
        fn hit(&self) -> Option<HitRecord<T>>;
    }
    
    impl<T: Material> Hittable<T> for Sphere<T> {
        fn hit(&self) -> Option<HitRecord<T>> {
            // snip
        }
    }
    

    Another way is to use an associated type (it models the situation better, but as long as you only implement the trait for one generic parameter it doesn't practically matter):

    pub trait Hittable {
        type T: Material;
        fn hit(&self) -> Option<HitRecord<Self::T>>;
    }
    
    impl<T: Material> Hittable for Sphere<T> {
        type T = T;
        fn hit(&self) -> Option<HitRecord<T>> {
            // snip
        }
    }