【quantity】3 Unit 物理量计算库(quantity.rs)

一、源码
下面代码是一个使用Rust实现的类型安全物理量计算库,支持单位自动推导和SI前缀转换。

//! 物理量计算库
//! 
//! 提供类型安全的物理量计算功能,支持单位自动推导和SI前缀转换

use typenum::{
    Integer, Sum, Diff, 
    Z0,     // 0
    P1, P2, P3, P6, P9, P12, P15, P18, P21, P24, P27, P30, // 正指数
    N1, N2, N3, N6, N9, N12, N15, N18, N21, N24, N27, N30  // 负指数
};
use super::unit::Unit;
use std::marker::PhantomData;
use std::ops::{Add, Sub, Mul, Div};
use std::ops::Deref;

/// 物理量基础结构(无类型约束)
/// 
/// # 类型参数
/// - `T`: 存储的数值类型
/// - `Prefix`: SI前缀类型(typenum中的整数类型)
/// - `U`: 单位类型
#[derive(Debug, Clone, Copy)]
pub struct Quantity<T, Prefix, U>
where
    Prefix: Integer,
    U: ?Sized,
{
    value: T,
    _marker: PhantomData<(Prefix, U)>,  // 合并Prefix和U的类型标记
}

impl<T, Prefix, U> Quantity<T, Prefix, U>
where
    Prefix: Integer,
    U: ?Sized,
{
    /// 获取值引用
    pub fn get(&self) -> &T {
        &self.value
    }
    
    /// 设置新值
    pub fn set(&mut self, value: T) {
        self.value = value;
    }
}

impl<T, Prefix, M, KG, S, A, K, MOL, CD> Quantity<T, Prefix, Unit<M, KG, S, A, K, MOL, CD>>
where
    Prefix: Integer,
    M: Integer,
    KG: Integer,
    S: Integer,
    A: Integer,
    K: Integer,
    MOL: Integer,
    CD: Integer,
{
    /// 创建新物理量
    /// 
    /// # 参数
    /// - `value`: 物理量的数值
    /// 
    /// # 示例
    /// ```
    /// use  quantity::quantity::Length;
    /// let length = Length::<f64>::new(5.0);
    /// ```
    pub fn new(value: T) -> Self {
        Self {
            value,
            _marker: PhantomData,
        }
    }
    
    /// 提取内部值
    pub fn into_inner(self) -> T {
        self.value
    }
    
    /// 转换前缀(不改变实际值)
    /// 
    /// # 类型参数
    /// - `NewPrefix`: 新的SI前缀类型
    pub fn with_prefix<NewPrefix>(self) -> Quantity<T, NewPrefix, Unit<M, KG, S, A, K, MOL, CD>>
    where
        NewPrefix: Integer,
    {
        Quantity::new(self.value)
    }
    
    /// 转换为无前缀形式
    pub fn without_prefix(self) -> Quantity<T, Z0, Unit<M, KG, S, A, K, MOL, CD>> {
        self.with_prefix()
    }
    
    /// 转换为指定前缀(自动调整值)
    /// 
    /// # 类型参数
    /// - `NewPrefix`: 目标SI前缀类型
    /// 
    /// # 约束
    /// - `T`: 必须支持从f64转换和乘法运算
    /// - `Prefix`和`NewPrefix`: 必须能计算差值
    /// 
    /// # 示例
    /// ```
    /// use  quantity::quantity::Length;
    /// use  quantity::quantity::Milli;
    /// use  quantity::quantity::Kilo;
    /// let length_m = Length::<f64, Kilo>::new(1.0); // 1 km
    /// let length_mm = length_m.convert_to::<Milli>(); // 1000 mm
    /// ```
    pub fn convert_to<NewPrefix>(self) -> Quantity<T, NewPrefix, Unit<M, KG, S, A, K, MOL, CD>>
    where
        T: Mul<Output = T> + From<f64>,
        Prefix: Integer + Sub<NewPrefix>,
        NewPrefix: Integer,
        Diff<Prefix, NewPrefix>: Integer,
    {
        let exponent: i32 = Prefix::to_i32() - NewPrefix::to_i32();
        let factor = 10.0_f64.powi(exponent);
        Quantity::new(self.value * T::from(factor))
    }
}

// ================ 运算实现 ================

impl<T, Prefix: Integer, U> Deref for Quantity<T, Prefix, U> {
    type Target = T;
    
    /// 解引用获取内部值
    fn deref(&self) -> &T { 
        &self.value 
    }
}

impl<T1, T2, Prefix, U> Add<Quantity<T2, Prefix, U>> for Quantity<T1, Prefix, U>
where
    T1: Add<T2>,                           // 支持 T1 + T2 运算
    Prefix: Integer,                       // 前缀必须是整数类型
    U: Clone,                              // 单位类型需要可克隆
    <T1 as Add<T2>>::Output: Clone,        // 加法结果类型需要可克隆
{
    type Output = Quantity<<T1 as Add<T2>>::Output, Prefix, U>;
    
    /// 物理量加法
    /// 
    /// # 注意
    /// 要求两个物理量有相同的单位和前缀
    fn add(self, rhs: Quantity<T2, Prefix, U>) -> Self::Output {
        Quantity {
            value: self.value + rhs.value,
            _marker: PhantomData,
        }
    }
}

impl<T1, T2, Prefix, U> Sub<Quantity<T2, Prefix, U>> for Quantity<T1, Prefix, U>
where
    T1: Sub<T2>,                           // 支持 T1 - T2 运算
    Prefix: Integer,                       // 前缀必须是整数类型
    U: Clone,                              // 单位类型需要可克隆
    <T1 as Sub<T2>>::Output: Clone,        // 减法结果类型需要可克隆
{
    type Output = Quantity<<T1 as Sub<T2>>::Output, Prefix, U>;
    
    /// 物理量减法
    /// 
    /// # 注意
    /// 要求两个物理量有相同的单位和前缀
    fn sub(self, rhs: Quantity<T2, Prefix, U>) -> Self::Output {
        Quantity {
            value: self.value - rhs.value,
            _marker: PhantomData,
        }
    }
}

impl<T1, T2, Prefix1, Prefix2, U1, U2> Mul<Quantity<T2, Prefix2, U2>> for Quantity<T1, Prefix1, U1>
where
    T1: Mul<T2>,  // 值类型可相乘
    Prefix1: Integer + Add<Prefix2>,
    Prefix2: Integer,
    U1: Mul<U2>,  // 使用标准乘法 trait
    Sum<Prefix1, Prefix2>: Integer, 
    <T1 as Mul<T2>>::Output: Clone,
    <U1 as Mul<U2>>::Output: Clone,
{
    type Output = Quantity<
        <T1 as Mul<T2>>::Output,
        Sum<Prefix1, Prefix2>, 
        <U1 as Mul<U2>>::Output  // 单位相乘
    >;
    
    /// 物理量乘法
    /// 
    /// # 注意
    /// 自动处理单位和前缀的乘法关系
    fn mul(self, rhs: Quantity<T2, Prefix2, U2>) -> Self::Output {
        Quantity {
            value: self.value * rhs.value,
            _marker: PhantomData,
        }
    }
}

impl<T1, T2, Prefix1, Prefix2, U1, U2> Div<Quantity<T2, Prefix2, U2>> for Quantity<T1, Prefix1, U1>
where
    T1: Div<T2>,
    Prefix1: Integer + Sub<Prefix2>,  
    Prefix2: Integer,
    U1: Div<U2>,
    Diff<Prefix1, Prefix2>: Integer,
    <T1 as Div<T2>>::Output: Clone,
    <U1 as Div<U2>>::Output: Clone,
{
    type Output = Quantity<
        <T1 as Div<T2>>::Output,
        Diff<Prefix1, Prefix2>,  // 前缀指数相减
        <U1 as Div<U2>>::Output
    >;
    
    /// 物理量除法
    /// 
    /// # 注意
    /// 自动处理单位和前缀的除法关系
    fn div(self, rhs: Quantity<T2, Prefix2, U2>) -> Self::Output {
        Quantity {
            value: self.value / rhs.value,
            _marker: PhantomData,
        }
    }
}

// ================ 类型别名 ================

// 基本单位
/// 长度 (米)
pub type Length<T, P = NoPrefix> = Quantity<T, P, Unit<P1, Z0, Z0, Z0, Z0, Z0, Z0>>;
/// 质量 (千克)
pub type Mass<T, P = NoPrefix> = Quantity<T, P, Unit<Z0, P1, Z0, Z0, Z0, Z0, Z0>>;
/// 时间 (秒)
pub type Time<T, P = NoPrefix> = Quantity<T, P, Unit<Z0, Z0, P1, Z0, Z0, Z0, Z0>>;
/// 电流 (安培)
pub type Current<T, P = NoPrefix> = Quantity<T, P, Unit<Z0, Z0, Z0, P1, Z0, Z0, Z0>>;
/// 温度 (开尔文)
pub type Temperature<T, P = NoPrefix> = Quantity<T, P, Unit<Z0, Z0, Z0, Z0, P1, Z0, Z0>>;
/// 物质的量 (摩尔)
pub type Amount<T, P = NoPrefix> = Quantity<T, P, Unit<Z0, Z0, Z0, Z0, Z0, P1, Z0>>;
/// 发光强度 (坎德拉)
pub type LuminousIntensity<T, P = NoPrefix> = Quantity<T, P, Unit<Z0, Z0, Z0, Z0, Z0, Z0, P1>>;

// 导出单位
/// 速度 (米/秒)
pub type Velocity<T, P = NoPrefix> = Quantity<T, P, Unit<P1, Z0, N1, Z0, Z0, Z0, Z0>>;
/// 加速度 (米/秒²)
pub type Acceleration<T, P = NoPrefix> = Quantity<T, P, Unit<P1, Z0, N2, Z0, Z0, Z0, Z0>>;
/// 力 (牛顿 = 千克·米/秒²)
pub type Force<T, P = NoPrefix> = Quantity<T, P, Unit<P1, P1, N2, Z0, Z0, Z0, Z0>>;
/// 能量 (焦耳 = 千克·米²/秒²)
pub type Energy<T, P = NoPrefix> = Quantity<T, P, Unit<P2, P1, N2, Z0, Z0, Z0, Z0>>;
/// 功率 (瓦特 = 千克·米²/秒³)
pub type Power<T, P = NoPrefix> = Quantity<T, P, Unit<P2, P1, N3, Z0, Z0, Z0, Z0>>;
/// 电压 (伏特 = 千克·米²/秒³·安培)
pub type Voltage<T, P = NoPrefix> = Quantity<T, P, Unit<P2, P1, N3, N1, Z0, Z0, Z0>>;

// SI前缀
/// 无前缀 (10^0)
pub type NoPrefix = Z0;

// 正前缀 (大数)
/// 昆它 (quetta) 10^30
pub type Quetta = P30;
/// 容那 (ronna) 10^27
pub type Ronna = P27;
/// 尧它 (yotta) 10^24
pub type Yotta = P24;
/// 泽它 (zetta) 10^21
pub type Zetta = P21;
/// 艾可萨 (exa) 10^18
pub type Exa = P18;
/// 拍它 (peta) 10^15
pub type Peta = P15;
/// 太拉 (tera) 10^12
pub type Tera = P12;
/// 吉咖 (giga) 10^9
pub type Giga = P9;
/// 兆 (mega) 10^6
pub type Mega = P6;
/// 千 (kilo) 10^3
pub type Kilo = P3;
/// 百 (hecto) 10^2
pub type Hecto = P2;
/// 十 (deca) 10^1
pub type Deca = P1;

// 负前缀 (小数)
/// 分 (deci) 10^-1
pub type Deci = N1;
/// 厘 (centi) 10^-2
pub type Centi = N2;
/// 毫 (milli) 10^-3
pub type Milli = N3;
/// 微 (micro) 10^-6
pub type Micro = N6;
/// 纳诺 (nano) 10^-9
pub type Nano = N9;
/// 皮可 (pico) 10^-12
pub type Pico = N12;
/// 飞母托 (femto) 10^-15
pub type Femto = N15;
/// 阿托 (atto) 10^-18
pub type Atto = N18;
/// 仄普托 (zepto) 10^-21
pub type Zepto = N21;
/// 幺科托 (yocto) 10^-24
pub type Yocto = N24;
/// 柔托 (ronto) 10^-27
pub type Ronto = N27;
/// 亏科托 (quecto) 10^-30
pub type Quecto = N30;

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_length_addition() {
        let l1 = Length::<f64>::new(5.0);
        let l2 = Length::<f64>::new(3.0);
        let sum = l1 + l2;
        assert_eq!(*sum, 8.0);
    }
    
    #[test]
    fn test_prefix_conversion() {
        let km = Length::<f64, Kilo>::new(1.0);
        let m = km.convert_to::<NoPrefix>();
        assert_eq!(*m, 1000.0);
        
        let mm = km.convert_to::<Milli>();
        assert_eq!(*mm, 1_000_000.0);
    }
    
    #[test]
    fn test_multiplication() {
        let length = Length::<f64>::new(2.0);
        let time = Time::<f64>::new(4.0);
        let velocity = length / time;
        assert_eq!(*velocity, 0.5);
        
        let acceleration = velocity / time;
        assert_eq!(*acceleration, 0.125);
    }
    
    #[test]
    fn test_force_calculation() {
        let mass = Mass::<f64>::new(10.0);
        let acceleration = Acceleration::<f64>::new(2.0);
        let force: Force<f64> = mass * acceleration;
        assert_eq!(*force, 20.0);
    }
    
    #[test]
    fn test_energy_calculation() {
        let force = Force::<f64>::new(5.0);
        let distance = Length::<f64>::new(3.0);
        let energy: Energy<f64> = force * distance;
        assert_eq!(*energy, 15.0);
    }
}

二、基础结构

Quantity 结构体
pub struct Quantity<T, Prefix, U>
where
    Prefix: Integer,
    U: ?Sized,
{
    value: T,
    _marker: PhantomData<(Prefix, U)>,
}
  • T: 存储的数值类型(如f64, f32等)

  • Prefix: SI前缀类型(使用typenum中的整数类型表示,如Kilo, Milli等)

  • U: 单位类型(使用Unit结构表示,前文有相关叙述)

  • _marker: 使用PhantomData来在编译期跟踪类型参数而不需要运行时存储

核心方法
  • new(): 创建新物理量

  • get()/set(): 获取/设置值

  • into_inner(): 提取内部值

  • with_prefix(): 转换前缀(不改变实际值)

  • without_prefix(): 转换为无前缀形式

  • convert_to(): 转换为指定前缀(自动调整值)

三、单位系统

单位系统使用7个基本SI单位的幂次组合表示,详见前文有相关叙述。简单解释如下。

Unit<M, KG, S, A, K, MOL, CD>

每个类型参数表示对应基本单位的指数:

  • M: 米(长度)

  • KG: 千克(质量)

  • S: 秒(时间)

  • A: 安培(电流)

  • K: 开尔文(温度)

  • MOL: 摩尔(物质的量)

  • CD: 坎德拉(发光强度)

四、运算实现

库实现了四种基本运算:

加法 (Add)
impl<T1, T2, Prefix, U> Add<Quantity<T2, Prefix, U>> for Quantity<T1, Prefix, U>
  • 要求两个量有相同单位和前缀

  • 结果保持原单位和前缀

减法 (Sub)
impl<T1, T2, Prefix, U> Sub<Quantity<T2, Prefix, U>> for Quantity<T1, Prefix, U>
  • 同样要求相同单位和前缀

  • 结果保持原单位和前缀

乘法 (Mul)
impl<T1, T2, Prefix1, Prefix2, U1, U2> Mul<Quantity<T2, Prefix2, U2>> for Quantity<T1, Prefix1, U1>
  • 单位和前缀会进行组合

  • 新前缀 = Prefix1 + Prefix2

  • 新单位 = U1 * U2(指数相加)

除法 (Div)
impl<T1, T2, Prefix1, Prefix2, U1, U2> Div<Quantity<T2, Prefix2, U2>> for Quantity<T1, Prefix1, U1>
  • 单位和前缀会进行组合

  • 新前缀 = Prefix1 - Prefix2

  • 新单位 = U1 / U2(指数相减)

五、预定义类型

基本单位类型
pub type Length<T, P = NoPrefix> = Quantity<T, P, Unit<P1, Z0, Z0, Z0, Z0, Z0, Z0>>;
pub type Mass<T, P = NoPrefix> = Quantity<T, P, Unit<Z0, P1, Z0, Z0, Z0, Z0, Z0>>;
// 其他基本单位...
导出单位类型
pub type Velocity<T, P = NoPrefix> = Quantity<T, P, Unit<P1, Z0, N1, Z0, Z0, Z0, Z0>>;
pub type Force<T, P = NoPrefix> = Quantity<T, P, Unit<P1, P1, N2, Z0, Z0, Z0, Z0>>;
// 其他导出单位...
SI前缀类型
pub type NoPrefix = Z0;  // 10^0
pub type Kilo = P3;      // 10^3
pub type Milli = N3;     // 10^-3
// 其他前缀...

六、测试用例

代码包含多个测试用例验证功能:

  • 长度加法

  • 前缀转换(如千米转米、毫米)

  • 乘除法运算(如长度/时间=速度)

  • 力和能量的计算

七、设计优势

  • 类型安全:编译时检查单位一致性,防止单位不匹配的运算

  • 零成本抽象:所有类型信息在编译期处理,运行时无额外开销

  • 自动单位推导:乘除法自动推导出正确的单位和前缀

  • 灵活的单位系统:可以表示任意SI导出单位

  • 前缀支持:内置完整的SI前缀系统,支持自动转换

这个库非常适合需要精确物理量计算的科学和工程应用,能有效防止单位错误导致的bug。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liuyuan77

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值