1
votes

In the below example implementing either one of those traits would work. Compiler doesn't let to override the implementation for specific types.

Is there any other way to achieve this?

trait Giver<T,U> {
    fn give_first(&self) -> T;
    fn give_second(&self) -> U;
}

struct Pair<T,U>(T,U);

impl<T,U> Giver<T,U> for Pair<T,U> where T:Clone, U:Clone {
    fn give_first(&self) -> T {
        (self.0).clone()
    }

    fn give_second(&self) -> U {
        (self.1).clone()
    }
}

//works 
impl Giver<i32, i32> for Pair<f32, f32> {
    fn give_first(&self) -> i32 {
        1
    }

    fn give_second(&self) -> i32 {
        2
    }
}


//error[E0119]: conflicting implementations of trait `Giver<f32, f32>` for type `Pair<f32, f32>`:
impl Giver<f32, f32> for Pair<f32, f32> {
    fn give_first(&self) -> f32 {
        1.0
    }

    fn give_second(&self) -> f32 {
        2.0
    }
}
1
Your implementation returning i32 (the one that works) does not override the generic trait implementation, because the types T and U in the Giver<T, U> trait do not match the types in the Pair<T, U>: a generic that would match the implementation you give would be impl<T, U, V, W> Giver<T, U> for Pair<V, W> (which does indeed conflict with the working implementation). I don't think you can do what you want, but I will leave the answer to someone more knowledgeable.Simon Doppler

1 Answers

1
votes
#![feature(specialization)]

trait Giver<T,U> {
    fn give_first(&self) -> T;
    fn give_second(&self) -> U;
}

#[derive(Debug)]
struct Pair<T,U>(T,U);

impl<T,U> Giver<T,U> for Pair<T,U> where T:Clone, U:Clone {
    default fn give_first(&self) -> T {
        (self.0).clone()
    }

    default fn give_second(&self) -> U {
        (self.1).clone()
    }
}

impl Giver<i32, i32> for Pair<f32, f32> {
    fn give_first(&self) -> i32 {
        1
    }

    fn give_second(&self) -> i32 {
        2
    }
}


impl Giver<f32, f32> for Pair<f32, f32> {
    fn give_first(&self) -> f32 {
        3.0
    }

    fn give_second(&self) -> f32 {
        4.0
    }
}

fn main() {
    {
        let p = Pair(0.0, 0.0);
        let first: i32 = p.give_first();
        let second: i32 = p.give_second();
        println!("{}, {}", first, second);  // 1, 2
    }

    {
        let p: Pair<f32, f32> = Pair(0.0, 0.0);
        let first: f32 = p.give_first();
        let second: f32 = p.give_second();
        println!("{}, {}", first, second);  // 3, 4
    }
}

rust nightly seems to support it if we explicitly specify the expected return type. I tried it with #![feature(specialization)]. There might be a more elegant solution (would wait for someone with more knowledge on this).

output: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=d618cd9b534a5ba49199a2efdcf607bd