源码
这是一个编译时量纲检查的物理单位库。
//! 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 (速度)
-
单位除法:验证 m / s 得到 m/s (速度)
-
复合单位:验证 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>;
九、设计优势
-
类型安全:杜绝运行时单位错误
-
零开销:所有检查在编译期完成
-
表达力强:可以表示任意复合单位
-
错误早发现:编译期捕获量纲不匹配
十、扩展方向
这个基础框架可以进一步扩展:
-
添加更多运算符(如平方、开方)
-
添加常用物理常量
-
支持用户自定义单位
总结来说,这段代码展示了如何利用 Rust 强大的类型系统来实现编译期的物理量纲检查,是类型安全编程的典范。