【PhysUnits】3 SI 量纲 实现解析(dimension/mod.rs)

源码

这是一个编译时量纲检查的物理单位库。

//! Physical Units Library with Type-Level Dimension Checking
//! 带类型级量纲检查的物理单位库
//!
//! This module provides type-safe physical unit representations using Rust's type system
//! to enforce dimensional correctness at compile time.
//! 本模块提供类型安全的物理单位表示,利用Rust类型系统在编译时强制量纲正确性
//!
//! # Examples | 示例
//! ```
//! use physunits::*;
//! use typenum::{P1, Z0, N1};
//!
//! // Define velocity unit (m/s)
//! // 定义速度单位 (米/秒)
//! type Velocity = Dimension<P1, Z0, N1, Z0, Z0, Z0, Z0>;
//!
//! // Define acceleration unit (m/s²)
//! // 定义加速度单位 (米/秒²)
//! type Acceleration = Dimension<P1, Z0, N2, Z0, Z0, Z0, Z0>;
//! ```
//!

use typenum::{Integer, Sum, Diff};
use core::marker::PhantomData;
use core::ops::{Add, Sub, Mul, Div};

pub use self::dimensional::Dimensional;
pub use self::alias::*;

mod dimensional;
mod alias;

/// Fundamental structure representing physical units with dimensional exponents
/// 表示带有量纲指数的物理单位的基础结构
///
/// # Type Parameters | 类型参数
/// - `METER`: Length dimension exponent | 长度量纲指数
/// - `KILOGRAM`: Mass dimension exponent | 质量量纲指数  
/// - `SECOND`: Time dimension exponent | 时间量纲指数
/// - `AMPERE`: Current dimension exponent | 电流量纲指数
/// - `KELVIN`: Temperature dimension exponent | 温度量纲指数
/// - `MOLE`: Amount dimension exponent | 物质量量纲指数
/// - `CANDELA`: Luminous intensity dimension exponent | 光强量纲指数
///
/// # Example | 示例
/// ```
/// use typenum::{P1, Z0, N1};
/// 
/// // Represents m¹·s⁻¹ (velocity) | 表示 m¹·s⁻¹ (速度)
/// type VelocityUnit = Dimension<P1, Z0, N1, Z0, Z0, Z0, Z0>;
/// 
/// // Represents m·kg·s⁻² (force) | 表示 m·kg·s⁻² (力)
/// type ForceUnit = Dimension<P1, P1, N2, Z0, Z0, Z0, Z0>;
/// ```
#[derive(Debug, Clone, Copy)]
pub struct Dimension<
    METER: Integer,
    KILOGRAM: Integer,
    SECOND: Integer,
    AMPERE: Integer,
    KELVIN: Integer,
    MOLE: Integer,
    CANDELA: Integer
>(
    PhantomData<(METER, KILOGRAM, SECOND, AMPERE, KELVIN, MOLE, CANDELA)>
);

impl<M: Integer, KG: Integer, S: Integer, A: Integer, K: Integer, MOL: Integer, CD: Integer>
Dimension<M, KG, S, A, K, MOL, CD> {
    /// Creates a new unit instance
    /// 创建新的单位实例
    pub fn new() -> Self {
        Self(PhantomData)
    }
}

// ========== Operator Implementations ==========
// ========== 运算符实现 ==========

impl<M1, M2, KG1, KG2, S1, S2, A1, A2, K1, K2, MOL1, MOL2, CD1, CD2> 
    Mul<Dimension<M2, KG2, S2, A2, K2, MOL2, CD2>> for Dimension<M1, KG1, S1, A1, K1, MOL1, CD1>
where
    M1: Integer + Add<M2>,
    M2: Integer,
    KG1: Integer + Add<KG2>,
    KG2: Integer,
    S1: Integer + Add<S2>,
    S2: Integer,
    A1: Integer + Add<A2>,
    A2: Integer,
    K1: Integer + Add<K2>,
    K2: Integer,
    MOL1: Integer + Add<MOL2>,
    MOL2: Integer,
    CD1: Integer + Add<CD2>,
    CD2: Integer,
    Sum<M1, M2>: Integer,
    Sum<KG1, KG2>: Integer,
    Sum<S1, S2>: Integer,
    Sum<A1, A2>: Integer,
    Sum<K1, K2>: Integer,
    Sum<MOL1, MOL2>: Integer,
    Sum<CD1, CD2>: Integer,
{
    type Output = Dimension<
        Sum<M1, M2>, Sum<KG1, KG2>, Sum<S1, S2>,
        Sum<A1, A2>, Sum<K1, K2>, Sum<MOL1, MOL2>, Sum<CD1, CD2>
    >;
    
    /// Multiplies two units by adding their dimensional exponents
    /// 通过相加量纲指数来相乘两个单位
    fn mul(self, _: Dimension<M2, KG2, S2, A2, K2, MOL2, CD2>) -> Self::Output {
        Dimension::new()
    }
}

impl<M1, M2, KG1, KG2, S1, S2, A1, A2, K1, K2, MOL1, MOL2, CD1, CD2> 
    Div<Dimension<M2, KG2, S2, A2, K2, MOL2, CD2>> for Dimension<M1, KG1, S1, A1, K1, MOL1, CD1>
where
    M1: Integer + Sub<M2>,
    M2: Integer,
    KG1: Integer + Sub<KG2>,
    KG2: Integer,
    S1: Integer + Sub<S2>,
    S2: Integer,
    A1: Integer + Sub<A2>,
    A2: Integer,
    K1: Integer + Sub<K2>,
    K2: Integer,
    MOL1: Integer + Sub<MOL2>,
    MOL2: Integer,
    CD1: Integer + Sub<CD2>,
    CD2: Integer,
    Diff<M1, M2>: Integer,
    Diff<KG1, KG2>: Integer,
    Diff<S1, S2>: Integer,
    Diff<A1, A2>: Integer,
    Diff<K1, K2>: Integer,
    Diff<MOL1, MOL2>: Integer,
    Diff<CD1, CD2>: Integer,
{
    type Output = Dimension<
        Diff<M1, M2>, Diff<KG1, KG2>, Diff<S1, S2>,
        Diff<A1, A2>, Diff<K1, K2>, Diff<MOL1, MOL2>, Diff<CD1, CD2>
    >;
    
    /// Divides two units by subtracting their dimensional exponents
    /// 通过相减量纲指数来相除两个单位
    fn div(self, _: Dimension<M2, KG2, S2, A2, K2, MOL2, CD2>) -> Self::Output {
        Dimension::new()
    }
}

/// 量纲除法结果类型 / Dimension division result type
pub type DimensionDiv<A, B> = <A as Div<B>>::Output;

/// 量纲乘法结果类型 / Dimension multiplication result type
pub type DimensionMul<A, B> = <A as Mul<B>>::Output;

// ========== Debugging and Testing Code ==========
// ========== 调试和测试代码 ==========

#[cfg(test)]
mod tests {
    use super::*;
    use typenum::{P1, Z0, N1, N2};
    
    /// Test unit multiplication
    /// 测试单位乘法
    #[test]
    fn test_unit_multiplication() {
        type Meter = Dimension<P1, Z0, Z0, Z0, Z0, Z0, Z0>;
        type Second = Dimension<Z0, Z0, P1, Z0, Z0, Z0, Z0>;
        type Velocity = DimensionMul<Meter, Dimension<Z0, Z0, N1, Z0, Z0, Z0, Z0>>;
        
        let _meter = Meter::new();
        let _second = Second::new();
        let _velocity: Velocity = Meter::new().mul(Second::new().div(Second::new()).div(Second::new()));
        
        // Compile-time check that velocity has correct dimensions (m/s)
        // 编译时检查速度有正确的量纲 (米/秒)
        let _: Dimension<P1, Z0, N1, Z0, Z0, Z0, Z0> = _velocity;
    }
    
    /// Test unit division
    /// 测试单位除法
    #[test]
    fn test_unit_division() {
        type Meter = Dimension<P1, Z0, Z0, Z0, Z0, Z0, Z0>;
        type Second = Dimension<Z0, Z0, P1, Z0, Z0, Z0, Z0>;
        type Velocity = DimensionDiv<Meter, Second>;
        
        let _velocity: Velocity = Meter::new().div(Second::new());
        
        // Compile-time check that velocity has correct dimensions (m/s)
        // 编译时检查速度有正确的量纲 (米/秒)
        let _: Dimension<P1, Z0, N1, Z0, Z0, Z0, Z0> = _velocity;
    }
    
    /// Test compound units
    /// 测试复合单位
    #[test]
    fn test_compound_units() {
        type Meter = Dimension<P1, Z0, Z0, Z0, Z0, Z0, Z0>;
        type Kilogram = Dimension<Z0, P1, Z0, Z0, Z0, Z0, Z0>;
        type Second = Dimension<Z0, Z0, P1, Z0, Z0, Z0, Z0>;
        
        // Force = kg·m/s²
        // 力 = 千克·米/秒²
        type Force = DimensionMul<Kilogram, DimensionDiv<Meter, DimensionMul<Second, Second>>>;
        
        let _force: Force = Kilogram::new().mul(Meter::new().div(Second::new().mul(Second::new())));
        
        // Compile-time check that force has correct dimensions (kg·m/s²)
        // 编译时检查力有正确的量纲 (千克·米/秒²)
        let _: Dimension<P1, P1, N2, Z0, Z0, Z0, Z0> = _force;
    }
}

二、核心设计理念

这段代码利用 Rust 的类型系统在编译期确保物理量计算的量纲正确性,通过泛型参数来表示各个基本单位的指数:

  • 使用 typenum crate 提供的类型级别数字(如 P1, Z0, N1 分别表示 +1, 0, -1)

  • 七个基本量纲对应国际单位制(SI)的七个基本单位:

    • 米(METER)、千克(KILOGRAM)、秒(SECOND)

    • 安培(AMPERE)、开尔文(KELVIN)、摩尔(MOLE)、坎德拉(CANDELA)

三、核心数据结构

pub struct Dimension<METER, KILOGRAM, SECOND, AMPERE, KELVIN, MOLE, CANDELA>(
    PhantomData<...>
);

这是一个零大小类型(ZST),使用 PhantomData 来持有类型参数但不占用运行时空间。每个类型参数代表对应基本单位的指数。

四、运算符重载

实现了两种核心运算:

  • 乘法运算 (Mul trait)
impl<...> Mul<Dimension<...>> for Dimension<...> {
    type Output = Dimension<Sum<...>, ...>;
    fn mul(self, _: Dimension<...>) -> Self::Output {
        Dimension::new()
    }
}

物理意义:当两个物理量相乘时,它们的量纲指数相加
示例:速度(m/s) × 时间(s) = 距离(m) → P1 + Z0 = P1 (米), N1 + P1 = Z0 (秒)

  • 除法运算 (Div trait)
impl<...> Div<Dimension<...>> for Dimension<...> {
    type Output = Dimension<Diff<...>, ...>;
    fn div(self, _: Dimension<...>) -> Self::Output {
        Dimension::new()
    }
}

物理意义:当两个物理量相除时,它们的量纲指数相减
示例:距离(m) ÷ 时间(s) = 速度(m/s) → P1 - Z0 = P1 (米), Z0 - P1 = N1 (秒)

###五、类型别名

pub type DimensionDiv<A, B> = <A as Div<B>>::Output;
pub type DimensionMul<A, B> = <A as Mul<B>>::Output;

这些别名简化了复合单位的类型声明,使代码更易读。

六、测试用例分析

测试代码验证了三种核心场景:

1.单位乘法:验证 m * (s/s²) 得到 m/s (速度)

  1. 单位除法:验证 m / s 得到 m/s (速度)

  2. 复合单位:验证 kg * (m/(s*s)) 得到 kg·m/s² (力/牛顿)

七、编译时检查机制

关键点在于:

  • 所有运算都在类型层面完成

  • 错误的量纲操作会在编译时报错

  • 测试中的 let _: Dimension<…> = … 是编译期断言

八、实际应用示例

// 定义基本单位
type Meter = Dimension<P1, Z0, Z0, Z0, Z0, Z0, Z0>;
type Second = Dimension<Z0, Z0, P1, Z0, Z0, Z0, Z0>;

// 导出速度单位
type Velocity = DimensionDiv<Meter, Second>; // m/s

// 导出加速度单位
type Acceleration = DimensionDiv<Velocity, Second>; // m/s²

// 导出力的单位 (kg·m/s²)
type Newton = DimensionMul<Kilogram, Acceleration>;

九、设计优势

  1. 类型安全:杜绝运行时单位错误

  2. 零开销:所有检查在编译期完成

  3. 表达力强:可以表示任意复合单位

  4. 错误早发现:编译期捕获量纲不匹配

十、扩展方向

这个基础框架可以进一步扩展:

  • 添加更多运算符(如平方、开方)

  • 添加常用物理常量

  • 支持用户自定义单位

总结来说,这段代码展示了如何利用 Rust 强大的类型系统来实现编译期的物理量纲检查,是类型安全编程的典范。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

liuyuan77

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

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

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

打赏作者

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

抵扣说明:

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

余额充值