< 返回版块

viruscamp 发表于 2020-10-13 22:53

Tags:const_generics

用 常量泛型(const_generics) 实现计量单位检查与转换
重新实现 测试实例:单位说明
https://doc.rust-lang.org/stable/rust-by-example/generics/phantom/testcase_units.html

rust 1.47 说是引入 const_generics 但好像只有系统库能用
还是要上 nightly 使用 rustc 1.49.0-nightly (8dae8cdcc 2020-10-12)

#![feature(const_generics)]

use core::ops::Add;
use core::marker::PhantomData;

trait LengthType<const F: f64> {}

#[derive(Debug, Clone, Copy)]
struct Length<const F: f64>(f64, PhantomData<dyn LengthType<F>>);

type Meter = Length<1.0>;
type Mm = Length<1000.0>;
type Inch = Length<{1000.0/25.4}>;

impl<const F1: f64> Length<F1> {
    fn new(val: f64) -> Self {
        Length(val, PhantomData)
    }

    fn value(self) -> f64 {
        self.0
    }

    fn factor() -> f64 {
        F1
    }

    fn _from<const F2: f64>(src: Length<F2>) -> Self {
        Self::new(src.0 * F1 / F2)
    }

    fn _into<const F2: f64>(self) -> Length<F2> {
        Length::new(self.0 * F2 / F1)
    }
}

impl<const F: f64> Add for Length<F> {
    type Output = Self;
    fn add(self, other: Self) -> Self::Output {
        Self::new(self.0 + other.0)
    }
}

fn main() {
    let m1 = Meter::new(1.0);
    let inch3 = Inch::new(3.0);
    let mm40 = Mm::new(40.0);

    let a = m1 + inch3._into();
    println!("m1 + inch3 = {} m", a.value());

    let b = mm40 + inch3._into();
    println!("mm40 + inch3 = {} mm", b.value());

    let c = mm40 + m1._into();
    println!("mm40 + m1 = {} mm", c.value());
}

输出为:

m1 + inch3 = 1.0762 m
mm40 + inch3 = 116.2 mm
mm40 + m1 = 1040 mm

还有几个遗留问题待解决:

// 1. 约束条件能做吗
trait LengthType<const F: f64> where F > 0.0 {}
// 2. 类型转换 From 怎么实现
impl<const F1: f64, const F2: f64> From<Length<F2>> for Length<F1> {}
// 3. 加法和减法 下面两种方法都能实现 那种比较好?  
impl<const F: f64> Add for Length<F> {} // let a = m1 + inch3._into();
impl<const F1: f64, const F2: f64> Add<Length<F2>> for Length<F1> {} // let b = m1 + inch3;

评论区

写评论
Mike Tang 2020-10-17 22:30

赞!同想学习类型编程。

1 共 1 条评论, 1 页