P.GEN.01 用泛型来抽象公共语义

【描述】

应该巧用泛型来抽象公共语义,消除重复代码。

【反例】

use std::ops::Add;

#[derive(Debug, Clone, Copy)]
struct Meter {
    value: f64
}

impl Meter {
    fn new(value: f64) -> Self {
        Self { value }
    }
}

impl Add for Meter {
    type Output = Meter;

    fn add(self, another: Meter) -> Self::Output {
        let value = self.value + another.value;
        Meter { value }
    }
}

#[derive(Debug, Clone, Copy)]
struct Kilogram {
    value: f64
}

impl Kilogram {
    fn new(value: f64) -> Self {
        Self { value }
    }
}

impl Add for Kilogram {
    type Output = Kilogram;

    fn add(self, another: Kilogram) -> Self::Output {
        let value = self.value + another.value;
        Kilogram { value }
    }
}
fn main() {
    // 不符合:如果要再新增新的单位,还需要实现很多重复代码
    let one_meter = Meter::new(1.0);
    let two_kilograms = Kilogram::new(2.0);
    
    let two_meters = one_meter + one_meter;
}

【正例】

use std::ops::Add;
use std::marker::PhantomData;

#[derive(Debug, Clone, Copy)]
struct Unit<T> {
    value: f64,
    unit_type: PhantomData<T>,
}

impl<T> Unit<T> {
    fn new(value: f64) -> Self {
        Self {
            value,
            unit_type: PhantomData,
        }
    }
}

impl<T> Add for Unit<T> {
    type Output = Unit<T>;

    fn add(self, another: Unit<T>) -> Self::Output {
        let new_value = self.value + another.value;
        Unit::new(new_value)
    }
}

#[derive(Debug, Clone, Copy)]
struct MeterType;

#[derive(Debug, Clone, Copy)]
struct KilogramType;

type Meter = Unit<MeterType>;
type Kilogram = Unit<KilogramType>;
fn main() {
    // 符合:如果要再新增新的单位,就方便很多了
    let one_meter = Meter::new(1.0);
    let two_kilograms = Kilogram::new(2.0);
    
    let two_meters = one_meter + one_meter;
}