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

项目结构

units/
├── Cargo.toml
├── src/
│   ├── lib.rs
│   ├── dimension.rs      # 核心量纲系统
│   ├── ops.rs            # 运算符重载
│   └── units/
│       ├── mod.rs
│       ├── base.rs       # 基本单位定义(不含时间和长度)
│       ├── time.rs       # 时间单位定义(从base.rs拆分)
│       ├── length.rs     # 长度单位定义(从base.rs拆分)
│       ├── derived.rs    # 导出单位定义
│       └── constants.rs  # 物理常数
└── tests/
    └── integration.rs    # 集成测试

项目文件

  1. Cargo.toml
[package]
name = "unit"
version = "0.1.0"
edition = "2024"
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::Unit;
pub use units::{base, derived, constants};

/// 预导入常用单位
pub mod prelude {
    pub use crate::dimension::Unit;
    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};

/// SI单位系统实现(带词条头支持)
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Unit<
    T,
    const PREFIX: i32 = 0,
    const METER: i32 = 0,
    const KILOGRAM: i32 = 0,
    const SECOND: i32 = 0,
    const AMPERE: i32 = 0,
    const KELVIN: i32 = 0,
    const MOLE: i32 = 0,
    const CANDELA: i32 = 0,
> {
    pub value: T,
}

// 词条头常量定义
pub const KILO: i32 = 3;
pub const MILLI: i32 = -3;
/* 其他前缀... */

impl<T, const P: i32, const M: i32, const KG: i32> 
    Unit<T, P, M, KG> 
{
    pub fn new(value: T) -> Self { Self { value } }
    
    pub fn cast<U: NumCast>(self) -> Option<Unit<U, P, M, KG>> {
        NumCast::from(self.value).map(Unit::new)
    }
}

impl<T: fmt::Display, const P: i32, const M: i32> 
    fmt::Display for Unit<T, P, M> 
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if P != 0 { write!(f, "×10^{} ", P)?; }
        /* 量纲显示逻辑 */
    }
}
  1. src/ops.rs - 运算符重载
use std::ops::{Add, Sub, Mul, Div};
use num_traits::Num;
impl<T, const P: i32> Add for Unit<T, P> {
    type Output = Self;
    fn add(self, rhs: Self) -> Self::Output {
        Unit::new(self.value + rhs.value)
    }
}

macro_rules! impl_binop {
    ($op:ident, $method:ident) => {
        impl<T, const P1: i32, const P2: i32> 
            $op<Unit<T, P2>> for Unit<T, P1> 
        {
            type Output = Unit<T, {P1 + P2}>;
            fn $method(self, rhs: Unit<T, P2>) -> Self::Output {
                Unit::new(self.value.$method(rhs.value))
            }
        }
    };
}
impl_binop!(Mul, mul);
impl_binop!(Div, div);
  1. src/units/ - 单位定义
  • mod.rs
pub mod base;
pub mod length; 
pub mod time; 
pub mod derived;
pub mod constants;

pub use base::*;
pub use length::*;
pub use time::*;
pub use derived::*;
pub use constants::*;
  • base.rs - 基本单位
use super::dimension::Unit;

/// 长度 - 米 (m)
pub type Meter<T> = Unit<T, 0, 1, 0, 0, 0, 0, 0, 0>;

/// 质量 - 千克 (kg)
pub type Kilogram<T> = Unit<T, 0, 0, 1, 0, 0, 0, 0, 0>;

/// 时间 - 秒 (s)
pub type Second<T> = Unit<T, 0,0,  0, 1, 0, 0, 0, 0>;

/// 电流 - 安培 (A)
pub type Ampere<T> = Unit<T,0, 0, 0, 0, 1, 0, 0, 0>;

/// 温度 - 开尔文 (K)
pub type Kelvin<T> = Unit<T, 0,0, 0, 0, 0, 1, 0, 0>;

/// 物质的量 - 摩尔 (mol)
pub type Mole<T> = Unit<T, 0, 0,0, 0, 0, 0, 1, 0>;

/// 发光强度 - 坎德拉 (cd)
pub type Candela<T> = Unit<T, 0,0, 0, 0, 0, 0, 0, 1>;
  • length.rs - 长度单位
use super::dimension::Unit;

/// 长度 - 米 (m)
pub type Meter<T> = Unit<T, 0, 1, 0, 0, 0, 0, 0, 0>;

/// 千米 (km)
pub type Kilometer<T> = Unit<T, KILO, 1, 0, 0, 0, 0, 0, 0>;

/// 毫米 (mm)
pub type Millimeter<T> = Unit<T, MILLI, 1, 0, 0, 0, 0, 0, 0>;
  • time.rs - 时间单位
use super::dimension::Unit;

/// 时间 - 秒 (s)
pub type Second<T> = Unit<T, 0, 0, 0, 1, 0, 0, 0, 0>;

/// 毫秒 (ms)
pub type Millisecond<T> = Unit<T, MILLI, 0, 0, 1, 0, 0, 0, 0>;

/// 小时 (h)
pub type Hour<T> = Unit<T, 0, 0, 0, 3600, 0, 0, 0, 0>;
  • derived.rs - 导出单位
use super::{base::*, dimension::Unit};

/// 频率 - 赫兹 (Hz = s⁻¹)
pub type Hertz<T> = Unit<T, 0, 0, -1, 0, 0, 0, 0>;

/// 力 - 牛顿 (N = kg·m·s⁻²)
pub type Newton<T> = Unit<T, 1, 0, 1, -2, 0, 0, 0, 0>;

/// 能量 - 焦耳 (J = N·m = kg·m²·s⁻²)
pub type Joule<T> = Unit<T, 2, 1, -2, 0, 0, 0, 0>;

/// 功率 - 瓦特 (W = J/s = kg·m²·s⁻³)
pub type Watt<T> = Unit<T, 2, 1, -3, 0, 0, 0, 0>;

/// 电压 - 伏特 (V = W/A = kg·m²·s⁻³·A⁻¹)
pub type Volt<T> = Unit<T, 2, 1, -3, -1, 0, 0, 0>;

/// 电阻 - 欧姆 (Ω = V/A = kg·m²·s⁻³·A⁻²)
pub type Ohm<T> = Unit<T, 2, 1, -3, -2, 0, 0, 0>;
  • constants.rs - 物理常数
use super::{base::*, dimension::Unit};

/// 光速 (m/s)
pub fn speed_of_light<T: crate::num_traits::Float>() -> Unit<T, 1, 0, -1, 0, 0, 0, 0> {
    Unit::new(T::from(299792458).unwrap()
}

/// 普朗克常数 (J·s)
pub fn planck_constant<T: crate::num_traits::Float>() -> Unit<T, 2, 1, -1, 0, 0, 0, 0> {
    Unit::new(T::from(6.62607015e-34).unwrap())
}

/// 阿伏伽德罗常数 (mol⁻¹)
pub fn avogadro_constant<T: crate::num_traits::Float>() -> Unit<T, 0, 0, 0, 0, 0, -1, 0> {
    Unit::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. 架构设计
类型系统架构:
Unit<T, PREFIX, 量纲...>
├─ 数值类型 T: 支持任意数值类型(f32/f64等)
├─ PREFIX: 词条头(10的幂次)
└─ 量纲参数: 7个基本量纲指数
运算规则:
  • 加法/减法:要求完全相同的量纲和词条头

  • 乘法/除法:量纲指数相加,词条头指数相加

  • 单位转换:需显式调用转换方法

  1. 关键特性
编译期量纲检查:
let length = Meter::new(5.0);
let time = Second::new(2.0);
let _ = length + time; // 编译错误:量纲不匹配
词条头处理:
let km = Kilometer::new(2.0);    // 2×10³ m
let mm = Meter::<f64, MILLI>::new(3000.0);  // 3000×10⁻³ m
let sum = km + mm; // 需要统一单位
零成本抽象:
// 编译后等价于直接操作f64
let force: Newton<f64> = Kilogram::new(2.0) * Meter::new(3.0) / (Second::new(1.0).powi(2);
  1. 使用方法示例
基本运算:
let speed = Kilometer::new(120.0) / Hour::new(2.0);
println!("Speed: {} m/s", speed.to_meters_per_second());

物理公式:

fn kinetic_energy<T>(mass: Kilogram<T>, velocity: MeterPerSecond<T>) -> Joule<T> 
where T: Float + Mul<Output = T>
{
    T::from(0.5).unwrap() * mass * velocity.powi(2)
}
单位转换:
let temp = Celsius::new(25.0);
let kelvin: Kelvin<_> = temp.into();
  1. 测试案例
#[test]
fn test_energy_calculation() {
    let mass = Kilogram::new(2.0);
    let velocity = MeterPerSecond::new(3.0);
    let energy = kinetic_energy(mass, velocity);
    assert_eq!(energy.value, 9.0);
}

#[test]
fn test_prefix_conversion() {
    let km = Kilometer::new(1.5);
    let meters: Meter<_> = km.convert();
    assert_eq!(meters.value, 1500.0);
}
  1. 扩展性设计

自定义单位:

pub type LightYear<T> = Unit<T, 0, 1, 0, 0, 0, 0, 0, 0>;
pub fn new_lightyear<T: Float>(value: T) -> LightYear<T> {
    Unit::new(value * T::from(9.461e15).unwrap())
}
支持新数值类型:
impl<T: MyBigFloat, const P: i32> Unit<T, P> {
    pub fn to_decimal_string(&self) -> String {
        format!("{}e{}", self.value, P)
    }
}
优势说明
  1. 类型安全:所有单位运算在编译期检查量纲一致性

  2. 高性能:无运行时开销,编译后与直接数值运算等效

  3. 表达力强:支持从阿托(10⁻¹⁸)到尧它(10²⁴)的词条头范围

  4. 可扩展:易于添加新的单位类型和特殊运算

  5. 符合SI标准:严格遵循国际单位制规范

该实现特别适合需要高精度单位管理的科学计算、工程仿真和金融计算等领域,在保证计算安全性的同时提供直观的单位表达方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

liuyuan77

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

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

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

打赏作者

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

抵扣说明:

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

余额充值