【quantity】2 Unit 结构体(unit.rs)
一、源码
下面代码实现了一个基于类型级别的物理量单位系统,使用Rust的类型系统在编译期保证单位运算的正确性。
use typenum::{Integer, Sum, Diff, Z0, // 0P1, P2, P3, P4, // +1, +2, +3, +4N1, N2, N3 // -1, -2, -3
};
use std::marker::PhantomData;
use std::ops::{Add, Sub, Mul, Div};/// 物理量基础结构(无类型约束)| Base structure for physical quantities (unconstrained type)
///
/// 使用泛型常量参数表示SI单位制的量纲 | Uses generic const parameters to represent SI unit dimensions
/// 参数顺序:米, 千克, 秒, 安培, 开尔文, 摩尔, 坎德拉 | Parameters: meter, kilogram, second, ampere, kelvin, mole, candela
///
/// 注意:虽然结构体包含7个类型参数,但实际上表示的是7个基本单位的指数。
/// 例如:Unit<P1, Z0, N1, Z0, Z0, Z0, Z0> 表示 m¹·s⁻¹ (速度单位)
///
/// 使用PhantomData来在编译期保持类型信息而不需要运行时存储
#[derive(Debug, Clone, Copy)]
pub struct Unit<METER, KILOGRAM, SECOND, AMPERE, KELVIN, MOLE, CANDELA>(PhantomData<(METER, KILOGRAM, SECOND, AMPERE, KELVIN, MOLE, CANDELA)>
) whereMETER: Integer,KILOGRAM: Integer,SECOND: Integer,AMPERE: Integer,KELVIN: Integer,MOLE: Integer,CANDELA: Integer;impl<M, KG, S, A, K, MOL, CD> Unit<M, KG, S, A, K, MOL, CD>
whereM: Integer,KG: Integer,S: Integer,A: Integer,K: Integer,MOL: Integer,CD: Integer,
{/// 创建新物理量 | Create new quantity/// /// 返回一个特定量纲的单位实例,不包含实际值/// Returns a unit instance with specific dimensions, without actual valuepub fn new() -> Self {Self(PhantomData)}
}// 实现乘法运算重载 | Implement multiplication operator overloading
///
/// 单位相乘时,对应的量纲指数相加
/// When multiplying units, the corresponding dimension exponents are added
impl<M1, M2, KG1, KG2, S1, S2, A1, A2, K1, K2, MOL1, MOL2, CD1, CD2> Mul<Unit<M2, KG2, S2, A2, K2, MOL2, CD2>> for Unit<M1, KG1, S1, A1, K1, MOL1, CD1>
whereM1: 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 = Unit<Sum<M1, M2>, Sum<KG1, KG2>, Sum<S1, S2>,Sum<A1, A2>, Sum<K1, K2>, Sum<MOL1, MOL2>, Sum<CD1, CD2>>;fn mul(self, _: Unit<M2, KG2, S2, A2, K2, MOL2, CD2>) -> Self::Output {Unit::new()}
}// 实现除法运算重载 | Implement division operator overloading
///
/// 单位相除时,对应的量纲指数相减
/// When dividing units, the corresponding dimension exponents are subtracted
impl<M1, M2, KG1, KG2, S1, S2, A1, A2, K1, K2, MOL1, MOL2, CD1, CD2> Div<Unit<M2, KG2, S2, A2, K2, MOL2, CD2>> for Unit<M1, KG1, S1, A1, K1, MOL1, CD1>
whereM1: 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 = Unit<Diff<M1, M2>, Diff<KG1, KG2>, Diff<S1, S2>,Diff<A1, A2>, Diff<K1, K2>, Diff<MOL1, MOL2>, Diff<CD1, CD2>>;fn div(self, _: Unit<M2, KG2, S2, A2, K2, MOL2, CD2>) -> Self::Output {Unit::new()}
}/* ================ SI基本单位(GB 3100-93 表1)| SI Base Units (GB 3100-93 Table P1) ================ *//// 长度 - 米 (m) | Length - meter (m)
///
/// 量纲表示: [L] = m¹
/// Dimension: [L] = m¹
pub type Meter = Unit<P1, Z0, Z0, Z0, Z0, Z0, Z0>;/// 质量 - 千克 (kg) | Mass - kilogram (kg)
///
/// 量纲表示: [M] = kg¹
/// Dimension: [M] = kg¹
pub type Kilogram = Unit<Z0, P1, Z0, Z0, Z0, Z0, Z0>;/// 时间 - 秒 (s) | Time - second (s)
///
/// 量纲表示: [T] = s¹
/// Dimension: [T] = s¹
pub type Second = Unit<Z0, Z0, P1, Z0, Z0, Z0, Z0>;/// 电流 - 安培 (A) | Electric current - ampere (A)
///
/// 量纲表示: [I] = A¹
/// Dimension: [I] = A¹
pub type Ampere = Unit<Z0, Z0, Z0, P1, Z0, Z0, Z0>;/// 温度 - 开尔文 (K) | Thermodynamic temperature - kelvin (K)
///
/// 量纲表示: [Θ] = K¹
/// Dimension: [Θ] = K¹
pub type Kelvin = Unit<Z0, Z0, Z0, Z0, P1, Z0, Z0>;/// 物质的量 - 摩尔 (mol) | Amount of substance - mole (mol)
///
/// 量纲表示: [N] = mol¹
/// Dimension: [N] = mol¹
pub type Mole = Unit<Z0, Z0, Z0, Z0, Z0, P1, Z0>;/// 发光强度 - 坎德拉 (cd) | Luminous intensity - candela (cd)
///
/// 量纲表示: [J] = cd¹
/// Dimension: [J] = cd¹
pub type Candela = Unit<Z0, Z0, Z0, Z0, Z0, Z0, P1>;/* ================ 包括SI辅助单位在内的具有专门名称的SI导出单位(GB 3100-93 表2)| SI Derived Units with Special Names (GB 3100-93 Table 2) ================ *//* === SI辅助单位 | SI Supplementary Units === *//// 弧度 (rad) - 平面角单位 m·m⁻¹ = 1 | Radian (rad) - plane angle unit m·m⁻¹ = 1
///
/// 量纲为1 | Dimensionless
pub type Radian = Unit<Z0, Z0, Z0, Z0, Z0, Z0, Z0>;/// 球面度 (sr) - 立体角单位 m²·m⁻² = 1 | Steradian (sr) - solid angle unit m²·m⁻² = 1
///
/// 量纲为1 | Dimensionless
pub type Steradian = Unit<Z0, Z0, Z0, Z0, Z0, Z0, Z0>;/* === 具有专门名称的SI导出单位 | SI Derived Units with Special Names === *//// 赫兹 (Hz) - 频率 s⁻¹ | Hertz (Hz) - frequency s⁻¹
///
/// 量纲表示: [T⁻¹] = s⁻¹
/// Dimension: [T⁻¹] = s⁻¹
pub type Hertz = Unit<Z0, Z0, N1, Z0, Z0, Z0, Z0>;/// 牛顿 (N) - 力 kg·m·s⁻² | Newton (N) - force kg·m·s⁻²
///
/// 量纲表示: [M L T⁻²] = kg¹·m¹·s⁻²
/// Dimension: [M L T⁻²] = kg¹·m¹·s⁻²
pub type Newton = Unit<P1, P1, N2, Z0, Z0, Z0, Z0>;/// 帕斯卡 (Pa) - 压力 N/m² = kg·m⁻¹·s⁻² | Pascal (Pa) - pressure N/m² = kg·m⁻¹·s⁻²
///
/// 量纲表示: [M L⁻¹ T⁻²] = kg¹·m⁻¹·s⁻²
/// Dimension: [M L⁻¹ T⁻²] = kg¹·m⁻¹·s⁻²
pub type Pascal = Unit<N1, P1, N2, Z0, Z0, Z0, Z0>;/// 焦耳 (J) - 能量 N·m = kg·m²·s⁻² | Joule (J) - energy N·m = kg·m²·s⁻²
///
/// 量纲表示: [M L² T⁻²] = kg¹·m²·s⁻²
/// Dimension: [M L² T⁻²] = kg¹·m²·s⁻²
pub type Joule = Unit<P2, P1, N2, Z0, Z0, Z0, Z0>;/// 瓦特 (W) - 功率 J/s = kg·m²·s⁻³ | Watt (W) - power J/s = kg·m²·s⁻³
///
/// 量纲表示: [M L² T⁻³] = kg¹·m²·s⁻³
/// Dimension: [M L² T⁻³] = kg¹·m²·s⁻³
pub type Watt = Unit<P2, P1, N3, Z0, Z0, Z0, Z0>;/// 库仑 (C) - 电量 A·s | Coulomb (C) - electric charge A·s
///
/// 量纲表示: [T I] = s¹·A¹
/// Dimension: [T I] = s¹·A¹
pub type Coulomb = Unit<Z0, Z0, P1, P1, Z0, Z0, Z0>;/// 伏特 (V) - 电位 W/A = kg·m²·s⁻³·A⁻¹ | Volt (V) - electric potential W/A = kg·m²·s⁻³·A⁻¹
///
/// 量纲表示: [M L² T⁻³ I⁻¹] = kg¹·m²·s⁻³·A⁻¹
/// Dimension: [M L² T⁻³ I⁻¹] = kg¹·m²·s⁻³·A⁻¹
pub type Volt = Unit<P2, P1, N3, N1, Z0, Z0, Z0>;/// 法拉 (F) - 电容 C/V = kg⁻¹·m⁻²·s⁴·A² | Farad (F) - capacitance C/V = kg⁻¹·m⁻²·s⁴·A²
///
/// 量纲表示: [M⁻¹ L⁻² T⁴ I²] = kg⁻¹·m⁻²·s⁴·A²
/// Dimension: [M⁻¹ L⁻² T⁴ I²] = kg⁻¹·m⁻²·s⁴·A²
pub type Farad = Unit<N2, N1, P4, P2, Z0, Z0, Z0>;/// 欧姆 (Ω) - 电阻 V/A = kg·m²·s⁻³·A⁻² | Ohm (Ω) - resistance V/A = kg·m²·s⁻³·A⁻²
///
/// 量纲表示: [M L² T⁻³ I⁻²] = kg¹·m²·s⁻³·A⁻²
/// Dimension: [M L² T⁻³ I⁻²] = kg¹·m²·s⁻³·A⁻²
pub type Ohm = Unit<P2, P1, N3, N2, Z0, Z0, Z0>;/// 西门子 (S) - 电导 Ω⁻¹ = kg⁻¹·m⁻²·s³·A² | Siemens (S) - conductance Ω⁻¹ = kg⁻¹·m⁻²·s³·A²
///
/// 量纲表示: [M⁻¹ L⁻² T³ I²] = kg⁻¹·m⁻²·s³·A²
/// Dimension: [M⁻¹ L⁻² T³ I²] = kg⁻¹·m⁻²·s³·A²
pub type Siemens = Unit<N2, N1, P3, P2, Z0, Z0, Z0>;/// 韦伯 (Wb) - 磁通量 V·s = kg·m²·s⁻²·A⁻¹ | Weber (Wb) - magnetic flux V·s = kg·m²·s⁻²·A⁻¹
///
/// 量纲表示: [M L² T⁻² I⁻¹] = kg¹·m²·s⁻²·A⁻¹
/// Dimension: [M L² T⁻² I⁻¹] = kg¹·m²·s⁻²·A⁻¹
pub type Weber = Unit<P2, P1, N2, N1, Z0, Z0, Z0>;/// 特斯拉 (T) - 磁感应强度 Wb/m² = kg·s⁻²·A⁻¹ | Tesla (T) - magnetic flux density Wb/m² = kg·s⁻²·A⁻¹
///
/// 量纲表示: [M T⁻² I⁻¹] = kg¹·s⁻²·A⁻¹
/// Dimension: [M T⁻² I⁻¹] = kg¹·s⁻²·A⁻¹
pub type Tesla = Unit<Z0, P1, N2, N1, Z0, Z0, Z0>;/// 亨利 (H) - 电感 Wb/A = kg·m²·s⁻²·A⁻² | Henry (H) - inductance Wb/A = kg·m²·s⁻²·A⁻²
///
/// 量纲表示: [M L² T⁻² I⁻²] = kg¹·m²·s⁻²·A⁻²
/// Dimension: [M L² T⁻² I⁻²] = kg¹·m²·s⁻²·A⁻²
pub type Henry = Unit<P2, P1, N2, N2, Z0, Z0, Z0>;/// 摄氏度 (℃) - 摄氏温度 (需特殊处理,量纲同开尔文,计划内部按开尔文存储,重载相应方法)
/// Celsius (℃) - Celsius temperature (requires special handling, same dimension as Kelvin, planned to store internally as Kelvin with overloaded methods)
///
/// 量纲表示: [Θ] = K¹ (与开尔文相同)
/// Dimension: [Θ] = K¹ (same as Kelvin)
pub type Celsius = Unit<Z0, Z0, Z0, Z0, P1, Z0, Z0>;/// 流明 (lm) - 光通量 cd·sr | Lumen (lm) - luminous flux cd·sr
///
/// 量纲表示: [J] = cd¹ (因为球面度无量纲)
/// Dimension: [J] = cd¹ (since steradian is dimensionless)
pub type Lumen = Unit<Z0, Z0, Z0, Z0, Z0, Z0, P1>;/// 勒克斯 (lx) - 照度 lm/m² = cd·sr·m⁻² | Lux (lx) - illuminance lm/m² = cd·sr·m⁻²
///
/// 量纲表示: [J L⁻²] = cd¹·m⁻²
/// Dimension: [J L⁻²] = cd¹·m⁻²
pub type Lux = Unit<N2, Z0, Z0, Z0, Z0, Z0, P1>;/* ================ 由于人类健康安全防范上的需要而确定的具有专门名称的SI导出单位(GB 3100-93 表3)| SI Derived Units with Special Names for Health Protection (GB 3100-93 Table 3) ================ *//// 贝可勒尔 (Bq) - 放射性活度 s⁻¹ (与Hz相同量纲) | Becquerel (Bq) - radioactivity s⁻¹ (same dimension as Hertz)
///
/// 量纲表示: [T⁻¹] = s⁻¹
/// Dimension: [T⁻¹] = s⁻¹
pub type Becquerel = Unit<Z0, Z0, N1, Z0, Z0, Z0, Z0>;/// 戈瑞 (Gy) - 吸收剂量 J/kg = m²·s⁻² | Gray (Gy) - absorbed dose J/kg = m²·s⁻²
///
/// 量纲表示: [L² T⁻²] = m²·s⁻²
/// Dimension: [L² T⁻²] = m²·s⁻²
pub type Gray = Unit<P2, Z0, N2, Z0, Z0, Z0, Z0>;/// 希沃特 (Sv) - 剂量当量 J/kg = m²·s⁻² (与Gy相同量纲) | Sievert (Sv) - dose equivalent J/kg = m²·s⁻² (same dimension as Gray)
///
/// 量纲表示: [L² T⁻²] = m²·s⁻²
/// Dimension: [L² T⁻²] = m²·s⁻²
pub type Sievert = Unit<P2, Z0, N2, Z0, Z0, Z0, Z0>;/// 新标准新增单位:卡特 (kat) - 催化活度 mol·s⁻¹ | Katal (kat) - catalytic activity mol·s⁻¹
///
/// 量纲表示: [N T⁻¹] = mol¹·s⁻¹
/// Dimension: [N T⁻¹] = mol¹·s⁻¹
pub type Katal = Unit<Z0, Z0, N1, Z0, Z0, P1, Z0>;/// 分贝 (dB) - 无量纲对数单位(需额外实现对数运算) | Decibel (dB) - dimensionless logarithmic unit (requires additional logarithmic operations)
///
/// 量纲为1 | Dimensionless
pub type Decibel = Unit<Z0, Z0, Z0, Z0, Z0, Z0, Z0>;// 测试代码
#[cfg(test)]
mod tests {use super::*;use typenum::{P1, N1, N2};#[test]fn basic_units() {let _m = Meter::new();let _kg = Kilogram::new();let _s = Second::new();let _a = Ampere::new();let _k = Kelvin::new();let _mol = Mole::new();let _cd = Candela::new();}#[test]fn derived_units() {let _hz = Hertz::new();let _n = Newton::new();let _pa = Pascal::new();let _j = Joule::new();let _w = Watt::new();let _c = Coulomb::new();let _v = Volt::new();let _f = Farad::new();let _ohm = Ohm::new();let _s = Siemens::new();let _wb = Weber::new();let _t = Tesla::new();let _h = Henry::new();let _lm = Lumen::new();let _lx = Lux::new();}#[test]fn multiplication() {// 测试单位乘法let _force: Newton = Kilogram::new() * Meter::new() / (Second::new() * Second::new());let _work: Joule = Newton::new() * Meter::new();let _power: Watt = Joule::new() / Second::new();// 电压 = 功率/电流let _voltage: Volt = Watt::new() / Ampere::new();}#[test]fn division() {// 测试单位除法let _speed: Unit<P1, Z0, N1, Z0, Z0, Z0, Z0> = Meter::new() / Second::new();let _accel: Unit<P1, Z0, N2, Z0, Z0, Z0, Z0> = Meter::new() / (Second::new() * Second::new());}#[test]fn dimensionless() {// 测试无量纲单位let _rad = Radian::new();let _sr = Steradian::new();// 弧度 = 弧长/半径 (m/m = 1)let _angle: Radian = Meter::new() / Meter::new();}#[test]fn health_units() {let _bq = Becquerel::new();let _gy = Gray::new();let _sv = Sievert::new();let _kat = Katal::new();let _db = Decibel::new();}
}
二、基础结构
Unit 结构体
pub struct Unit<METER, KILOGRAM, SECOND, AMPERE, KELVIN, MOLE, CANDELA>(PhantomData<(METER, KILOGRAM, SECOND, AMPERE, KELVIN, MOLE, CANDELA)>
) whereMETER: Integer,KILOGRAM: Integer,// ... 其他约束
-
这是一个泛型结构体,使用7个类型参数分别表示SI单位制中的7个基本量纲的指数
-
使用PhantomData来在编译期保持类型信息而不需要运行时存储
-
每个类型参数都有Integer约束,表示它们必须是整数类型
量纲表示
代码注释中解释了参数顺序和含义:
-
参数顺序:米(meter), 千克(kilogram), 秒(second), 安培(ampere), 开尔文(kelvin), 摩尔(mole), 坎德拉(candela)
-
例如:Unit<P1, Z0, N1, Z0, Z0, Z0, Z0> 表示 m¹·s⁻¹ (速度单位)
三、基本运算实现
乘法运算
impl<M1, M2, KG1, KG2, ...> Mul<Unit<M2, KG2, ...>> for Unit<M1, KG1, ...>
{type Output = Unit<Sum<M1, M2>, Sum<KG1, KG2>, ...>;fn mul(self, _: Unit<M2, KG2, ...>) -> Self::Output {Unit::new()}
}
-
实现乘法运算时,对应的量纲指数相加
-
使用typenum的Sum类型来计算类型级别的整数加法
-
例如:米(m) * 秒(s) = Unit<P1, Z0, Z0,…> * Unit<Z0, Z0, P1,…> = Unit<P1, Z0, P1,…>
除法运算
impl<M1, M2, KG1, KG2, ...> Div<Unit<M2, KG2, ...>> for Unit<M1, KG1, ...>
{type Output = Unit<Diff<M1, M2>, Diff<KG1, KG2>, ...>;fn div(self, _: Unit<M2, KG2, ...>) -> Self::Output {Unit::new()}
}
-
实现除法运算时,对应的量纲指数相减
-
使用typenum的Diff类型来计算类型级别的整数减法
-
例如:米(m) / 秒(s) = Unit<P1, Z0, Z0,…> / Unit<Z0, Z0, P1,…> = Unit<P1, Z0, N1,…>
四、SI基本单位和导出单位
代码定义了完整的SI单位系统,包括:
基本单位 (GB 3100-93 表1)
-
Meter - 米 (m)
-
Kilogram - 千克 (kg)
-
Second - 秒 (s)
-
Ampere - 安培 (A)
-
Kelvin - 开尔文 (K)
-
Mole - 摩尔 (mol)
-
Candela - 坎德拉 (cd)
具有专门名称的导出单位 (GB 3100-93 表2)
-
Radian - 弧度 (rad)
-
Steradian - 球面度 (sr)
-
Hertz - 赫兹 (Hz)
-
Newton - 牛顿 (N)
-
Pascal - 帕斯卡 (Pa)
-
Joule - 焦耳 (J)
-
Watt - 瓦特 (W)
-
Coulomb - 库仑 ©
-
Volt - 伏特 (V)
-
Farad - 法拉 (F)
-
Ohm - 欧姆 (Ω)
-
Siemens - 西门子 (S)
-
Weber - 韦伯 (Wb)
-
Tesla - 特斯拉 (T)
-
Henry - 亨利 (H)
-
Celsius - 摄氏度 (℃)
-
Lumen - 流明 (lm)
-
Lux - 勒克斯 (lx)
健康防护相关单位 (GB 3100-93 表3)
-
Becquerel - 贝可勒尔 (Bq)
-
Gray - 戈瑞 (Gy)
-
Sievert - 希沃特 (Sv)
-
Katal - 卡特 (kat)
-
Decibel - 分贝 (dB)
无、测试代码
测试代码验证了各种单位和运算的正确性:
#[test]
fn multiplication() {// 测试单位乘法let _force: Newton = Kilogram::new() * Meter::new() / (Second::new() * Second::new());let _work: Joule = Newton::new() * Meter::new();let _power: Watt = Joule::new() / Second::new();// 电压 = 功率/电流let _voltage: Volt = Watt::new() / Ampere::new();
}
这些测试验证了:
-
力的单位 (kg·m/s²) 确实等于牛顿
-
功的单位 (N·m) 确实等于焦耳
-
功率的单位 (J/s) 确实等于瓦特
-
电压的单位 (W/A) 确实等于伏特
六、设计特点
-
编译期检查:所有单位运算都在编译期进行类型检查,确保量纲正确性
-
零运行时开销:使用PhantomData,实际运行时没有任何额外开销
-
类型安全:防止不同物理量之间的错误运算
-
可扩展性:可以方便地添加新的单位或运算
七、使用示例
虽然代码中没有实际值的操作,但可以想象这样使用:
let length = Quantity::<Meter, f32>::new(5.0); // 5.0 米
let time = Quantity::<Second, f32>::new(2.0); // 2.0 秒
let speed = length / time; // 类型为 Quantity<Unit<P1, Z0, N1, ...>, f32>
这个系统可以防止诸如"5米 + 2秒"这样的非法运算,因为编译器会在编译期捕获这种类型错误。
八、总结
这段代码展示了一个强大的类型级物理单位系统实现,利用Rust的类型系统和typenum库在编译期保证物理量运算的正确性。这种设计模式在需要严格类型安全的科学计算、工程应用中非常有用。