当前位置: 首页 > news >正文

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

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

//! 物理量计算库
//! 
//! 提供类型安全的物理量计算功能,支持单位自动推导和SI前缀转换use typenum::{Integer, Sum, Diff, Z0,     // 0P1, 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>
wherePrefix: Integer,U: ?Sized,
{value: T,_marker: PhantomData<(Prefix, U)>,  // 合并Prefix和U的类型标记
}impl<T, Prefix, U> Quantity<T, Prefix, U>
wherePrefix: 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>>
wherePrefix: 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>>whereNewPrefix: 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>>whereT: 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>
whereT1: 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>
whereT1: 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>
whereT1: Mul<T2>,  // 值类型可相乘Prefix1: Integer + Add<Prefix2>,Prefix2: Integer,U1: Mul<U2>,  // 使用标准乘法 traitSum<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>
whereT1: 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>
wherePrefix: 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。

http://www.xdnf.cn/news/197893.html

相关文章:

  • c语言的指针详解
  • js补环境工具使用技巧、补环境实例、重点环境检测点详解
  • Qt开发:XML文件的写入与读取
  • AI与机器人外科手术:如何用智能化技术提升手术精度与安全性?
  • 【android bluetooth 协议分析 06】【l2cap详解 10】【通过avdtp连接流程,感受l2cap通道的生命周期变化】
  • [JavaScript]对象关联风格与行为委托模式
  • WSL释放空间
  • ‌wangEditor 所有菜单项分类、说明及隐藏方法
  • Java项目场景题深度解析
  • Termux - Android终端应用与Linux环境
  • Java读Excel:解析阿里云easyExcel导入文件的行号
  • vmare pro安装报错用户在命令行上发出了EULAS_AGREED=1,表示不接受许可协议的错误解决方法
  • 高压开关柜局部放电信号分析系统
  • C/C++链表的常用操作实现
  • three.js后处理原理及源码分析
  • HTML5好看的水果蔬菜在线商城网站源码系列模板7
  • 文档在线协同工具ONLYOFFICE教程:如何使用宏突出显示具有特定提示文本的空文本字段
  • window 图形显示驱动-在 WDDM 1.2 中提供无缝状态转换(下)
  • 系统架构师2025年论文《论面向对象的软件设计——UML 在面向对象软件架构中的应用》
  • leetcode 876. 链表的中间结点
  • Python 实现的运筹优化系统数学建模详解(动态规划模型)
  • 第二阶段:基础加强阶段总体介绍
  • 网络安全怎么入门?快速了解
  • 基于大模型的公安预审办案笔录分析的挑战与应对策略-3
  • 2025汽车制造企业数字化转型路径参考
  • TypeScript之基础知识
  • vue报错:Loading chunk * failed,vue-router懒加载出错问题。
  • C++复习补充 类型转换和RTTI
  • 人工智能与机器学习:Python从零实现K-Means 算法
  • RAG工程-基于LangChain 实现 Advanced RAG(预检索优化)