1
votes

I'm reading through the "Advanced Traits" section of the Rust book where there's an example of adding two types that are not the same:

use std::ops::Add;

struct Millimeters(u32);
struct Meters(u32);

impl Add<Meters> for Millimeters {
    type Output = Millimeters;

    fn add(self, other: Meters) -> Millimeters {
        Millimeters(self.0 + (other.0 * 1000))
    }
}

Suppose that I had a trait that both Millimeters and Meters implemented which specifies how to turn itself into metres (and assuming Millimeters and Meters implement this):

trait Length {
    fn to_meters(&self) -> Meters;
}

Is there some way to write a more generic Add trait that looks something like this (which is not valid):

impl Add<T: Length> for Millimeters {
    type Output = Meters;

    fn add(&self, other: &T) -> Meters {
        let as_meters = other.to_meters();
        Meters((self.0 / 1000) + (as_meters.0))
    }
} 
1

1 Answers

1
votes

Yes, except you've inexplicably put the trait bound in the wrong spot and changed the function signature to references instead of values. Fixing that makes it work:

impl<T: Length> Add<T> for Millimeters {
    type Output = Meters;

    fn add(self, other: T) -> Meters {
        let as_meters = other.to_meters();
        Meters((self.0 / 1000) + (as_meters.0))
    }
}

I'd use Into and a where clause though:

impl<T> Add<T> for Millimeters
where
    T: Into<Meters>,
{
    type Output = Meters;

    fn add(self, other: T) -> Meters {
        let as_meters = other.into();
        Meters((self.0 / 1000) + (as_meters.0))
    }
}