【PhysUnits】17.6 Unit基础结构(unit.rs)
一、源码
这段代码定义了一个用于物理量单位系统的Unit结构体及其相关操作,支持单位自动推导和类型安全的运算。
//! Unit基础结构
//!
//! 支持单位自动推导use core::marker::PhantomData;
use core::ops::{Neg, Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign};use crate::sealed::Sealed;
use super::{Si, Sied};
use super::ratio::{NoRatio, Scaled};
use super::Dimensional;
use super::prefix::Prefixed;
use crate::variable::{Numeric, Scalar, Var};
use super::Unitary;// ========== 辅助trait和实现 ==========
// 辅助trait,用于规范类型
pub trait UnitOrSi {type Output;fn unit(self) -> Self::Output;
}// 为所有Prefixed类型实现UnitOrSi
impl<S: Sied, R: Scaled> UnitOrSi for Unit<S, R> {type Output = Self;fn unit(self) -> Self::Output{self}
}impl<S: Sied> UnitOrSi for Unit<S, NoRatio> {type Output = S;fn unit(self) -> Self::Output{self.0}
}/// Unit基础结构
///
/// # 类型参数
/// - `R`: 比例因子类型
/// - `S`: SI基础类型
#[derive(Debug, Clone, Copy)]
pub struct Unit<S: Sied, R>(pub S,pub PhantomData<R>);impl<T, D, Pr, R> Unit<Si<Var<T>, D, Pr>, R>
where T: Numeric,D: Dimensional,Pr: Prefixed,Var<T>: Scalar,R: Scaled,
{pub fn new(value: T) -> Self {Self(Si::new(value),PhantomData)}
}impl< S: Sied, R: Scaled> Sealed for Unit<S, R>{}impl<S: Sied, R: Scaled> Unitary for Unit<S, R>{}// ================ 运算实现 ================// ----- 取负运算符 -----
impl<S: Sied, R: Scaled> Neg for Unit<S, R>
whereS: Neg<Output = S>,
{type Output = Self;/// 取负运算(保持单位和比例因子不变)fn neg(self) -> Self::Output {Unit(-self.0, PhantomData)}
}// ----- 加法运算符及其赋值 -----
// U + U
impl<S: Sied, R: Scaled> Add for Unit<S, R>
whereS: Sied + Add<S, Output = S>,R: Scaled,
{type Output = Self;/// 物理量乘法fn add(self, rhs: Self) -> Self::Output {Unit(self.0 + rhs.0, PhantomData)}
}// U += U
impl<S: Sied, R: Scaled> AddAssign for Unit<S, R>
whereS: Sied + AddAssign,R: Scaled,
{/// 加法赋值fn add_assign(&mut self, rhs: Self){self.0 += rhs.0;}
}// U += T
impl<T:Numeric, S: Sied, R: Scaled> AddAssign<T> for Unit<S, R>
whereS: Sied + AddAssign<T>,R: Scaled,
{/// 加法赋值fn add_assign(&mut self, rhs: T){self.0 += rhs;}
}// U += Var<T>
impl<T:Numeric, S: Sied, R: Scaled> AddAssign<Var<T>> for Unit<S, R>
whereS: Sied + AddAssign<Var<T>>,R: Scaled,
{/// 加法赋值fn add_assign(&mut self, rhs: Var<T>){self.0 += rhs;}
}// ----- 减法运算符及减法赋值 -----
// U - U
impl<S: Sied, R: Scaled> Sub for Unit<S, R>
whereS: Sied + Sub<S, Output = S>,R: Scaled,
{type Output = Self;/// 物理量乘法fn sub(self, rhs: Self) -> Self::Output {Unit(self.0 - rhs.0, PhantomData)}
}// U -= U
impl<S: Sied, R: Scaled> SubAssign for Unit<S, R>
whereS: Sied + SubAssign,R: Scaled,
{/// 加法赋值fn sub_assign(&mut self, rhs: Self){self.0 -= rhs.0;}
}// U -= T
impl<T:Numeric, S: Sied, R: Scaled> SubAssign<T> for Unit<S, R>
whereS: Sied + SubAssign<T>,R: Scaled,
{/// 加法赋值fn sub_assign(&mut self, rhs: T){self.0 -= rhs;}
}// U -= Var<T>
impl<T:Numeric, S: Sied, R: Scaled> SubAssign<Var<T>> for Unit<S, R>
whereS: Sied + SubAssign<Var<T>>,R: Scaled,
{/// 加法赋值fn sub_assign(&mut self, rhs: Var<T>){self.0 -= rhs;}
}// ----- 乘法运算符及乘法赋值 -----// U * U
impl<S1, S2, R1, R2> Mul<Unit<S2, R2>> for Unit<S1, R1>
whereS1: Sied + Mul<S2, Output: Sied>,S2: Sied,R1: Scaled + Mul<R2, Output: Scaled>,R2: Scaled,Unit<<S1 as Mul<S2>>::Output,<R1 as Mul<R2>>::Output>: UnitOrSi,
{type Output = <Unit<<S1 as Mul<S2>>::Output,<R1 as Mul<R2>>::Output> as UnitOrSi>::Output;/// 物理量乘法fn mul(self, rhs: Unit<S2, R2>) -> Self::Output {Unit(self.0 * rhs.0, PhantomData).unit()}
}// U * SI
//因为编译器对U * T与U * Si无法区分,Si必须用Si<Var<T>, D, Pr>表示
impl<S, R, T, D, Pr> Mul<Si<Var<T>, D, Pr>> for Unit<S, R>
whereT: Numeric,Var<T>: Scalar,D: Dimensional,Pr: Prefixed,S: Sied + Mul<Si<Var<T>, D, Pr>, Output: Sied>,Si<Var<T>, D, Pr>: Sied,R: Scaled,
{type Output = Unit<<S as Mul<Si<Var<T>, D, Pr>>>::Output, // 单位相乘R>;/// 物理量乘法fn mul(self, rhs: Si<Var<T>, D, Pr>) -> Self::Output {Unit(self.0 * rhs, PhantomData)}
}// U * Var<T>
impl<S, R, T> Mul<Var<T>> for Unit<S, R>
whereT:Numeric,Var<T>: Scalar,S: Sied + Mul<Var<T>, Output: Sied>,R: Scaled,
{type Output = Unit<<S as Mul<Var<T>>>::Output,R>;/// 物理量乘法fn mul(self, rhs: Var<T>) -> Self::Output {Unit(self.0 * rhs, PhantomData)}
}// U * T
impl<T, S, R> Mul<T> for Unit<S, R>
whereT: Numeric,Var<T>: Scalar,S: Sied + Mul<T, Output: Sied>,R: Scaled,
{type Output = Unit<<S as Mul<T>>::Output,R>;/// 物理量乘法fn mul(self, rhs: T) -> Self::Output {Unit(self.0 * rhs, PhantomData)}
}// U *= Var<T>
impl<T, S, R> MulAssign<Var<T>> for Unit<S, R>
whereT: Numeric,S: Sied + MulAssign<Var<T>>,R: Scaled,Var<T>: Scalar,
{/// 标量乘法赋值 (*=)fn mul_assign(&mut self, rhs: Var<T>) {self.0 *= rhs;}
}// U *= T
impl<T, S, R> MulAssign<T> for Unit<S, R>
whereT: Numeric,S: Sied + MulAssign<Var<T>>,R: Scaled,Var<T>: Scalar,
{/// 标量乘法赋值 (*=)fn mul_assign(&mut self, rhs: T) {self.0 *= Var(rhs);}
}// ----- 除法运算符及除法赋值 -----// U / U
impl<S1, S2, R1, R2> Div<Unit<S2, R2>> for Unit<S1, R1>
whereS1: Sied + Div<S2, Output: Sied>,S2: Sied,R1: Scaled + Div<R2, Output: Scaled>,R2: Scaled,Unit<<S1 as Div<S2>>::Output, // 单位相除<R1 as Div<R2>>::Output>: UnitOrSi,
{type Output = <Unit<<S1 as Div<S2>>::Output, // 单位相除<R1 as Div<R2>>::Output> as UnitOrSi>::Output;/// 物理量除法fn div(self, rhs: Unit<S2, R2>) -> Self::Output {Unit(self.0 / rhs.0, PhantomData).unit()}
}// U / SI
//因为编译器对U / T与U / Si无法区分,Si必须用Si<Var<T>, D, Pr>表示
impl<S, R, T, D, Pr> Div<Si<Var<T>, D, Pr>> for Unit<S, R>
whereT: Numeric,Var<T>: Scalar,D: Dimensional,Pr: Prefixed,S: Sied + Div<Si<Var<T>, D, Pr>, Output: Sied>,Si<Var<T>, D, Pr>: Sied,R: Scaled,
{type Output = Unit<<S as Div<Si<Var<T>, D, Pr>>>::Output, // 单位相除R>;/// 物理量除法fn div(self, rhs: Si<Var<T>, D, Pr>) -> Self::Output {Unit(self.0 / rhs, PhantomData)}
}// U / Var<T>
impl<S, R, T> Div<Var<T>> for Unit<S, R>
whereT:Numeric,Var<T>: Scalar,S: Sied + Div<Var<T>, Output: Sied>,R: Scaled,
{type Output = Unit<<S as Div<Var<T>>>::Output,R>;/// 物理量除法fn div(self, rhs: Var<T>) -> Self::Output {Unit(self.0 / rhs, PhantomData)}
}// U / T
impl<T, S, R> Div<T> for Unit<S, R>
whereT: Numeric,Var<T>: Scalar,S: Sied + Div<T, Output: Sied>,R: Scaled,
{type Output = Unit<<S as Div<T>>::Output,R>;/// 物理量除法fn div(self, rhs: T) -> Self::Output {Unit(self.0 / rhs, PhantomData)}
}// U /= Var<T>
impl<T, S, R> DivAssign<Var<T>> for Unit<S, R>
whereT: Numeric,S: Sied + DivAssign<Var<T>>,R: Scaled,Var<T>: Scalar,
{/// 标量除法赋值 (/=)fn div_assign(&mut self, rhs: Var<T>) {self.0 /= rhs;}
}// U /= T
impl<T, S, R> DivAssign<T> for Unit<S, R>
whereT: Numeric,S: Sied + DivAssign<Var<T>>,R: Scaled,Var<T>: Scalar,
{/// 标量除法赋值 (/=)fn div_assign(&mut self, rhs: T) {self.0 /= Var(rhs);}
}
二、核心结构
pub struct Unit<S: Sied, R>(pub S, pub PhantomData<R>);
-
Unit是一个泛型结构体,包含两个类型参数:
-
S: Sied:表示SI基础类型(如米、千克等)
-
R: Scaled:表示比例因子类型(如千分之一、百分之一等)
-
-
使用PhantomData来标记比例因子类型R,使其在运行时没有实际存储
三、主要功能
- 单位转换与规范化
通过UnitOrSi trait提供单位转换能力:
pub trait UnitOrSi {type Output;fn unit(self) -> Self::Output;
}
-
当比例因子R是NoRatio时,返回SI基础类型S
-
否则返回Unit自身
- 构造方法
pub fn new(value: T) -> Self {Self(Si::new(value), PhantomData)
}
- 创建一个新的Unit实例,包装给定的数值和单位
- 运算符重载
代码实现了丰富的运算符重载,支持类型安全的物理量运算:
算术运算
-
取负(Neg)
-
加法(Add, AddAssign)
-
减法(Sub, SubAssign)
-
乘法(Mul, MulAssign)
-
除法(Div, DivAssign)
运算特点
-
运算时会自动处理单位和比例因子的组合
-
支持与标量(T)、变量(Var)和SI单位(Si)的运算
-
乘法/除法会组合/抵消单位和比例因子
四、类型安全设计
-
使用泛型和trait bound确保只有兼容的单位才能进行运算
-
通过Sied(SI单位)、Scaled(比例因子)、Dimensional(量纲)等trait约束运算合法性
-
使用PhantomData在类型系统中携带比例因子信息而不增加运行时开销
五、使用场景
这个Unit结构体可用于构建类型安全的物理量计算系统,例如:
let length = Unit::<Meter, NoRatio>::new(5.0); // 5米
let time = Unit::<Second, Kilo>::new(2.0); // 2千秒
let speed = length / time; // 自动推导出适当的单位和比例因子
这样的设计可以在编译期捕获单位不匹配的错误,避免运行时单位换算错误。