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

【TeamFlow】4.3.1 SI单位系统库(Units)

项目结构

units/
├── Cargo.toml
├── src/
│   ├── lib.rs
│   ├── dimension.rs
│   ├── ops.rs
│   └── units/
│       ├── mod.rs
│       ├── base.rs
│       ├── derived.rs
│       └── constants.rs
└── tests/└── integration.rs

项目文件

  1. Cargo.toml
[package]
name = "si-units"
version = "0.1.0"
edition = "2021"
description = "Type-safe SI units implementation in Rust"
license = "MIT OR Apache-2.0"
repository = "https://github.com/example/si-units"[dependencies]
num-traits = "0.2"  # 提供数值类型的通用操作
num = "0.4"        # 额外的数值类型支持[dev-dependencies]
approx = "0.5"     # 用于测试中的浮点比较
  1. src/lib.rs - 库根模块
//! 类型安全的SI单位系统实现
//!
//! 提供编译期量纲检查的单位运算能力#![warn(missing_docs)]
#![forbid(unsafe_code)]pub mod dimension;
pub mod ops;
pub mod units;pub use dimension::SIUnit;
pub use units::{base, derived, constants};/// 预导入常用单位
pub mod prelude {pub use crate::dimension::SIUnit;pub use crate::units::base::*;pub use crate::units::derived::*;pub use crate::units::constants::*;pub use crate::ops::*;
}
  1. src/dimension.rs - 核心量纲系统
use std::fmt;
use num_traits::{Num, NumCast, Float};/// SI单位系统的7个基本量纲
///
/// 使用const泛型参数表示各基本单位的指数:
/// - METER: 米 (长度)
/// - KILOGRAM: 千克 (质量)
/// - SECOND: 秒 (时间)
/// - AMPERE: 安培 (电流)
/// - KELVIN: 开尔文 (温度)
/// - MOLE: 摩尔 (物质的量)
/// - CANDELA: 坎德拉 (发光强度)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SIUnit<T,const METER: i32,const KILOGRAM: i32,const SECOND: i32,const AMPERE: i32,const KELVIN: i32,const MOLE: i32,const CANDELA: i32,
> {/// 单位的数值部分pub value: T,
}impl<T, const M: i32, const KG: i32, const S: i32, const A: i32, const K: i32, const MOL: i32, const CD: i32>SIUnit<T, M, KG, S, A, K, MOL, CD>
{/// 创建新单位值pub fn new(value: T) -> Self {Self { value }}/// 转换数值类型pub fn cast<U: NumCast>(self) -> Option<SIUnit<U, M, KG, S, A, K, MOL, CD>> {NumCast::from(self.value).map(|v| SIUnit::new(v))}
}impl<T: fmt::Display, const M: i32, const KG: i32, const S: i32, const A: i32, const K: i32, const MOL: i32, const CD: i32>fmt::Display for SIUnit<T, M, KG, S, A, K, MOL, CD>
{fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {write!(f, "{} ", self.value)?;let dims = [("m", M), ("kg", KG), ("s", S),("A", A), ("K", K), ("mol", MOL), ("cd", CD)];for (symbol, exp) in dims {if *exp != 0 {write!(f, "·{}{}", symbol, superscript(*exp))?;}}Ok(())}
}/// 将数字转换为上标格式
fn superscript(n: i32) -> String {let mut s = String::new();for c in n.to_string().chars() {s.push(match c {'-' => '⁻','0' => '⁰','1' => '¹','2' => '²','3' => '³','4' => '⁴','5' => '⁵','6' => '⁶','7' => '⁷','8' => '⁸','9' => '⁹',_ => c,});}s
}
  1. src/ops.rs - 运算符重载
use std::ops::{Add, Sub, Mul, Div, Neg};
use crate::dimension::SIUnit;// 相同量纲的加减法
impl<T: Add<Output = U>, U, const M: i32, const KG: i32, const S: i32, const A: i32, const K: i32, const MOL: i32, const CD: i32>Add<SIUnit<T, M, KG, S, A, K, MOL, CD>> for SIUnit<T, M, KG, S, A, K, MOL, CD>
{type Output = SIUnit<U, M, KG, S, A, K, MOL, CD>;fn add(self, rhs: SIUnit<T, M, KG, S, A, K, MOL, CD>) -> Self::Output {SIUnit::new(self.value + rhs.value)}
}impl<T: Sub<Output = U>, U, const M: i32, const KG: i32, const S: i32, const A: i32, const K: i32, const MOL: i32, const CD: i32>Sub<SIUnit<T, M, KG, S, A, K, MOL, CD>> for SIUnit<T, M, KG, S, A, K, MOL, CD>
{type Output = SIUnit<U, M, KG, S, A, K, MOL, CD>;fn sub(self, rhs: SIUnit<T, M, KG, S, A, K, MOL, CD>) -> Self::Output {SIUnit::new(self.value - rhs.value)}
}// 乘除法 - 自动计算新量纲
macro_rules! impl_binop {($op:ident, $method:ident, ($($dim:ident),+) => {impl<T: $op<U, Output = V>, U, V, $(const $dim: i32),+, $(const RHS_$dim: i32),+>$op<SIUnit<U, $(RHS_$dim),+>> for SIUnit<T, $($dim),+>{type Output = SIUnit<V, $($dim + RHS_$dim),+>;fn $method(self, rhs: SIUnit<U, $(RHS_$dim),+>) -> Self::Output {SIUnit::new(self.value.$method(rhs.value))}}};
}impl_binop!(Mul, mul, METER, KILOGRAM, SECOND, AMPERE, KELVIN, MOLE, CANDELA);
impl_binop!(Div, div, METER, KILOGRAM, SECOND, AMPERE, KELVIN, MOLE, CANDELA);// 实现取反
impl<T: Neg<Output = U>, U, const M: i32, const KG: i32, const S: i32, const A: i32, const K: i32, const MOL: i32, const CD: i32>Neg for SIUnit<T, M, KG, S, A, K, MOL, CD>
{type Output = SIUnit<U, M, KG, S, A, K, MOL, CD>;fn neg(self) -> Self::Output {SIUnit::new(-self.value)}
}
  1. src/units/ - 单位定义
  • base.rs - 基本单位
use super::dimension::SIUnit;/// 长度 - 米 (m)
pub type Meter<T> = SIUnit<T, 1, 0, 0, 0, 0, 0, 0>;/// 质量 - 千克 (kg)
pub type Kilogram<T> = SIUnit<T, 0, 1, 0, 0, 0, 0, 0>;/// 时间 - 秒 (s)
pub type Second<T> = SIUnit<T, 0, 0, 1, 0, 0, 0, 0>;/// 电流 - 安培 (A)
pub type Ampere<T> = SIUnit<T, 0, 0, 0, 1, 0, 0, 0>;/// 温度 - 开尔文 (K)
pub type Kelvin<T> = SIUnit<T, 0, 0, 0, 0, 1, 0, 0>;/// 物质的量 - 摩尔 (mol)
pub type Mole<T> = SIUnit<T, 0, 0, 0, 0, 0, 1, 0>;/// 发光强度 - 坎德拉 (cd)
pub type Candela<T> = SIUnit<T, 0, 0, 0, 0, 0, 0, 1>;
  • derived.rs - 导出单位
use super::{base::*, dimension::SIUnit};/// 频率 - 赫兹 (Hz = s⁻¹)
pub type Hertz<T> = SIUnit<T, 0, 0, -1, 0, 0, 0, 0>;/// 力 - 牛顿 (N = kg·m·s⁻²)
pub type Newton<T> = SIUnit<T, 1, 1, -2, 0, 0, 0, 0>;/// 能量 - 焦耳 (J = N·m = kg·m²·s⁻²)
pub type Joule<T> = SIUnit<T, 2, 1, -2, 0, 0, 0, 0>;/// 功率 - 瓦特 (W = J/s = kg·m²·s⁻³)
pub type Watt<T> = SIUnit<T, 2, 1, -3, 0, 0, 0, 0>;/// 电压 - 伏特 (V = W/A = kg·m²·s⁻³·A⁻¹)
pub type Volt<T> = SIUnit<T, 2, 1, -3, -1, 0, 0, 0>;/// 电阻 - 欧姆 (Ω = V/A = kg·m²·s⁻³·A⁻²)
pub type Ohm<T> = SIUnit<T, 2, 1, -3, -2, 0, 0, 0>;
  • constants.rs - 物理常数
use super::{base::*, dimension::SIUnit};/// 光速 (m/s)
pub fn speed_of_light<T: crate::num_traits::Float>() -> SIUnit<T, 1, 0, -1, 0, 0, 0, 0> {SIUnit::new(T::from(299792458).unwrap()
}/// 普朗克常数 (J·s)
pub fn planck_constant<T: crate::num_traits::Float>() -> SIUnit<T, 2, 1, -1, 0, 0, 0, 0> {SIUnit::new(T::from(6.62607015e-34).unwrap())
}/// 阿伏伽德罗常数 (mol⁻¹)
pub fn avogadro_constant<T: crate::num_traits::Float>() -> SIUnit<T, 0, 0, 0, 0, 0, -1, 0> {SIUnit::new(T::from(6.02214076e23).unwrap())
}
  1. tests/integration.rs - 集成测试
use si_units::prelude::*;
use approx::assert_relative_eq;#[test]
fn test_force_calculation() {let mass = Kilogram::new(5.0);let acceleration = Meter::new(2.0) / (Second::new(1.0) * Second::new(1.0));let force: Newton<f64> = mass * acceleration;assert_eq!(force.value, 10.0);
}#[test]
fn test_energy_calculation() {let force = Newton::new(10.0);let distance = Meter::new(3.0);let energy: Joule<f64> = force * distance;assert_eq!(energy.value, 30.0);
}#[test]
fn test_display_formatting() {let resistance = Ohm::new(4.7);assert_eq!(format!("{}", resistance), "4.7 ·kg¹·m²·s⁻³·A⁻²");
}#[test]
fn test_physical_constants() {let c: MeterPerSecond<f64> = speed_of_light();assert_relative_eq!(c.value, 299792458.0, epsilon = 1.0);let h = planck_constant::<f64>();assert_relative_eq!(h.value, 6.62607015e-34, max_relative = 1e-9);
}

设计亮点解析

  1. 类型安全的量纲系统
  • 使用const泛型在编译期跟踪每个单位的量纲指数

  • 非法运算(如 米 + 秒)会导致编译错误

  1. 零成本抽象
  • 所有量纲检查在编译期完成

  • 运行时等同于直接操作基础数值类型

  1. 灵活的数值支持
  • 通过泛型支持任意数值类型(f32, f64, 自定义类型等)

  • 兼容num-traits生态系统

  1. 清晰的物理关系表达
  • 导出单位自动继承正确的量纲关系

  • 如 牛顿 = 千克 × 米 / 秒² 直接体现在类型系统中

  1. 完备的显示支持
  • 自动格式化为标准科学表示法

  • 支持上标等专业数学符号

这个实现提供了强大的类型安全保证,同时保持了Rust的零成本抽象原则,非常适合科学计算、工程模拟等需要严格单位控制的场景。

相关文章:

  • 《MySQL 核心技能:SQL 查询与数据库概述》
  • 达梦官方管理工具 SQLark 更新--不仅支持达梦、Oracle、MySQL,还新增 PostgreSQL 数据库!
  • android 发送onkey广播,Android 添加键值并上报从驱动到上层
  • PerfettoSQL
  • 【RAG】一篇文章介绍多模态RAG(MRAG)
  • 电商虚拟户分账系统:破解电商资金管理难题的密钥
  • 蓝牙耳机开发--提示音制作生成的方法
  • 深入探索RAG:用LlamaIndex为大语言模型扩展知识,实现智能检索增强生成
  • Win10 关闭自动更新、关闭自动更新并重启
  • Jetson Orin NX 16G 配置GO1强化学习运行环境
  • 深度学习中的“重参数化”总结
  • 互联网大厂Java面试:软件架构与大型网站架构设计的较量
  • 操作系统-用户级-内核级线程
  • IOT项目——物联网 GPS
  • 25.4.22华为--算法真题整理(2025年4月22日)
  • 全本地化智能数字人
  • 一个 HTTP 请求进入 Spring MVC 应用后,大致经历了哪些主要步骤?
  • 电商平台数据采集与 QPS 计算全流程解析
  • 逻辑思维与软件开发:从选定方向到风险管理的全流程
  • Linux DRM显示驱动框架技术总结
  • 海港负国安主场两连败,五强争冠卫冕冠军开始掉队
  • 新华时评:需要“重新平衡”的是美国心态
  • 首部关于民营经济发展的基础性法律,有何亮点?专家解读
  • 近七成科创板公司2024年营收增长,285家营收创历史新高
  • 中国强镇密码丨洪泽湖畔的蒋坝,如何打破古镇刻板印象
  • 广东雷州农商行董事长、原行长同日被查