模块概述这是一个 Rust 语言中用于表示**粗略时段Period**的模块专门用于计划性场景如3个月后交付不涉及精确的时间计算。核心设计理念仅用于计划场景适用于项目计划、合同期限等需要粗略时间估算的场景可正可负支持正向和反向的时间偏移不混入更小单位不包含日或更细粒度因为无锚定时这些单位没有意义内部统一存储所有值最终转换为月数months: i64存储数据结构pubstructPeriod{pub(crate)months:i64,// 内部统一以月为单位存储}使用i64类型存储月数支持正负值字段可见性为pub(crate)仅在 crate 内部可见常量定义constMONTHS_PER_YEAR:i6412;constMONTHS_PER_QUARTER:i643;定义了时间单位之间的换算关系。构造方法方法说明示例from_months(months)从月数构造Period::from_months(6)→ 6个月from_years(years)从年数构造×12Period::from_years(2)→ 24个月from_quarters(quarters)从季度数构造×3Period::from_quarters(2)→ 6个月zero()构造零时段Period::zero()→ 0个月视图方法基本判断方法方法说明返回值as_months()获取总月数i64is_zero()是否为零boolis_positive()是否为正数boolis_negative()是否为负数bool单位转换方法方法说明示例as_years()获取年数向下取整13个月 → 1年as_quarters()获取季度数向下取整13个月 → 4季度remaining_months()不足一年的剩余月数13个月 → 1个月remaining_months_after_quarters()不足一个季度的剩余月数13个月 → 1个月其他方法方法说明abs()取绝对值重要设计细节使用欧几里得除法div_euclid对负数向下取整。例如 -13个月 -2年余11个月。链式方法支持流畅的链式调用方便构建复杂时段letpPeriod::from_months(1).m(2)// 加2个月.y(1)// 加1年12个月.q(1);// 加1季度3个月// 结果1 2 12 3 18个月方法说明m(months)增加指定月数y(years)增加指定年数自动×12q(quarters)增加指定季度数自动×3运算符重载实现了常用的算术运算符运算符说明示例时段相加p1 p2-时段相减p2 - p1-一元取负-p1*乘以整数p1 * 2/除以整数欧几里得除法p2 / 2迭代器求和实现了Sumtrait支持对 Period 集合求和letperiodsvec![Period::from_months(1),Period::from_months(2),Period::from_months(3),];lettotal:Periodperiods.iter().sum();// 6个月使用场景示例1. 基本构造和运算// 表示2年3个月letperiodPeriod::from_years(2).m(3);assert_eq!(period.as_months(),27);// 计算总时间letdelivery_timePeriod::from_months(3);letbufferPeriod::from_months(1);lettotaldelivery_timebuffer;// 4个月2. 批量求和letperiodsvec![Period::from_months(2),Period::from_months(3),Period::from_months(5),];lettotal:Periodperiods.iter().sum();// 10个月3. 正负时段处理letpositivePeriod::from_months(3);letnegativePeriod::from_months(-3);assert!(positive.is_positive());assert!(negative.is_negative());assert_eq!(negative.abs().as_months(),3);4. 链式构建复杂时段// 构建1年 2季度 3个月letcomplexPeriod::zero().y(1).q(2).m(3);assert_eq!(complex.as_months(),1263);// 21个月设计优势类型安全通过类型系统区分时段和普通整数避免混淆语义清晰使用年/月/季度等业务术语代码自解释运算完备支持加减乘除和求和方便批量计算不可变性所有方法返回新实例保证线程安全计划友好专为计划场景设计不涉及不精确的日单位适用场景项目计划与排期合同期限管理投资周期计算里程碑规划任何需要以年/月为单位进行粗略时间计算的场景不适用场景需要精确到天的时间计算跨时区时间处理需要考虑闰年、月份天数差异的场景需要锚定具体日期的时间运算完整代码// // period.rs// //! 粗略时段Periodusestd::ops::{Add,Sub,Mul,Div,Neg};// 常量 constMONTHS_PER_YEAR:i6412;constMONTHS_PER_QUARTER:i643;/// 粗略时段以年、月为单位的计划性时间长度////// - 仅用于计划场景如3个月后交付/// - 可正可负/// - ❌ 不混入日或更小单位无锚定时无意义#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]pubstructPeriod{pub(crate)months:i64,}implPeriod{// 构造方法 pubconstfnfrom_months(months:i64)-Self{Self{months}}pubconstfnfrom_years(years:i64)-Self{Self{months:years*MONTHS_PER_YEAR}}pubconstfnfrom_quarters(quarters:i64)-Self{Self{months:quarters*MONTHS_PER_QUARTER}}pubconstfnzero()-Self{Self{months:0}}// 视图方法 pubconstfnas_months(self)-i64{self.months}pubconstfnis_zero(self)-bool{self.months0}pubconstfnis_positive(self)-bool{self.months0}pubconstfnis_negative(self)-bool{self.months0}pubconstfnas_years(self)-i64{self.months.div_euclid(MONTHS_PER_YEAR)}pubconstfnas_quarters(self)-i64{self.months.div_euclid(MONTHS_PER_QUARTER)}pubconstfnremaining_months_after_quarters(self)-i64{self.months.rem_euclid(MONTHS_PER_QUARTER)}pubconstfnremaining_months(self)-i64{self.months.rem_euclid(MONTHS_PER_YEAR)}pubconstfnabs(self)-Self{Self{months:self.months.abs()}}// 链式方法 pubconstfnm(mutself,months:i64)-Self{self.monthsmonths;self}pubconstfny(mutself,years:i64)-Self{self.monthsyears*MONTHS_PER_YEAR;self}pubconstfnq(mutself,quarters:i64)-Self{self.monthsquarters*MONTHS_PER_QUARTER;self}}// 运算符重载 implAddforPeriod{typeOutputSelf;fnadd(self,rhs:Self)-Self{Self{months:self.monthsrhs.months}}}implSubforPeriod{typeOutputSelf;fnsub(self,rhs:Self)-Self{Self{months:self.months-rhs.months}}}implNegforPeriod{typeOutputSelf;fnneg(self)-Self{Self{months:-self.months}}}implMuli64forPeriod{typeOutputSelf;fnmul(self,rhs:i64)-Self{Self{months:self.months*rhs}}}implDivi64forPeriod{typeOutputSelf;fndiv(self,rhs:i64)-Self{Self{months:self.months.div_euclid(rhs)}}}implstd::iter::SumforPeriod{fnsumI:IteratorItemSelf(iter:I)-Self{iter.fold(Period::zero(),|acc,p|accp)}}implastd::iter::SumaPeriodforPeriod{fnsumI:IteratorItemaPeriod(iter:I)-Self{iter.fold(Period::zero(),|acc,p|acc*p)}}// // 测试// #[cfg(test)]modtests{usesuper::*;#[test]fntest_construction(){assert_eq!(Period::from_months(6).as_months(),6);assert_eq!(Period::from_years(1).as_months(),12);assert_eq!(Period::from_quarters(2).as_months(),6);assert_eq!(Period::zero().as_months(),0);}#[test]fntest_chain(){letpPeriod::from_months(1).m(2).y(1).q(1);// 1 2 12 3 18assert_eq!(p.as_months(),18);}#[test]fntest_as_methods(){letpPeriod::from_months(13);assert_eq!(p.as_years(),1);assert_eq!(p.as_quarters(),4);assert_eq!(p.remaining_months_after_quarters(),1);assert_eq!(p.remaining_months(),1);// 负数向下取整letpPeriod::from_months(-13);assert_eq!(p.as_years(),-2);assert_eq!(p.as_quarters(),-5);assert_eq!(p.remaining_months_after_quarters(),2);assert_eq!(p.remaining_months(),11);}#[test]fntest_operators(){letp1Period::from_months(3);letp2Period::from_months(5);assert_eq!((p1p2).as_months(),8);assert_eq!((p2-p1).as_months(),2);assert_eq!((p1*2).as_months(),6);assert_eq!((p2/2).as_months(),2);assert_eq!((-p1).as_months(),-3);}#[test]fntest_abs(){letpPeriod::from_months(-3);assert_eq!(p.abs().as_months(),3);}#[test]fntest_is_zero_positive_negative(){assert!(Period::zero().is_zero());assert!(Period::from_months(1).is_positive());assert!(Period::from_months(-1).is_negative());}#[test]fntest_sum(){letperiodsvec![Period::from_months(1),Period::from_months(2),Period::from_months(3),];lettotal:Periodperiods.iter().sum();assert_eq!(total.as_months(),6);lettotal:Periodperiods.into_iter().sum();assert_eq!(total.as_months(),6);}}
【A11】Period 模块代码解析
模块概述这是一个 Rust 语言中用于表示**粗略时段Period**的模块专门用于计划性场景如3个月后交付不涉及精确的时间计算。核心设计理念仅用于计划场景适用于项目计划、合同期限等需要粗略时间估算的场景可正可负支持正向和反向的时间偏移不混入更小单位不包含日或更细粒度因为无锚定时这些单位没有意义内部统一存储所有值最终转换为月数months: i64存储数据结构pubstructPeriod{pub(crate)months:i64,// 内部统一以月为单位存储}使用i64类型存储月数支持正负值字段可见性为pub(crate)仅在 crate 内部可见常量定义constMONTHS_PER_YEAR:i6412;constMONTHS_PER_QUARTER:i643;定义了时间单位之间的换算关系。构造方法方法说明示例from_months(months)从月数构造Period::from_months(6)→ 6个月from_years(years)从年数构造×12Period::from_years(2)→ 24个月from_quarters(quarters)从季度数构造×3Period::from_quarters(2)→ 6个月zero()构造零时段Period::zero()→ 0个月视图方法基本判断方法方法说明返回值as_months()获取总月数i64is_zero()是否为零boolis_positive()是否为正数boolis_negative()是否为负数bool单位转换方法方法说明示例as_years()获取年数向下取整13个月 → 1年as_quarters()获取季度数向下取整13个月 → 4季度remaining_months()不足一年的剩余月数13个月 → 1个月remaining_months_after_quarters()不足一个季度的剩余月数13个月 → 1个月其他方法方法说明abs()取绝对值重要设计细节使用欧几里得除法div_euclid对负数向下取整。例如 -13个月 -2年余11个月。链式方法支持流畅的链式调用方便构建复杂时段letpPeriod::from_months(1).m(2)// 加2个月.y(1)// 加1年12个月.q(1);// 加1季度3个月// 结果1 2 12 3 18个月方法说明m(months)增加指定月数y(years)增加指定年数自动×12q(quarters)增加指定季度数自动×3运算符重载实现了常用的算术运算符运算符说明示例时段相加p1 p2-时段相减p2 - p1-一元取负-p1*乘以整数p1 * 2/除以整数欧几里得除法p2 / 2迭代器求和实现了Sumtrait支持对 Period 集合求和letperiodsvec![Period::from_months(1),Period::from_months(2),Period::from_months(3),];lettotal:Periodperiods.iter().sum();// 6个月使用场景示例1. 基本构造和运算// 表示2年3个月letperiodPeriod::from_years(2).m(3);assert_eq!(period.as_months(),27);// 计算总时间letdelivery_timePeriod::from_months(3);letbufferPeriod::from_months(1);lettotaldelivery_timebuffer;// 4个月2. 批量求和letperiodsvec![Period::from_months(2),Period::from_months(3),Period::from_months(5),];lettotal:Periodperiods.iter().sum();// 10个月3. 正负时段处理letpositivePeriod::from_months(3);letnegativePeriod::from_months(-3);assert!(positive.is_positive());assert!(negative.is_negative());assert_eq!(negative.abs().as_months(),3);4. 链式构建复杂时段// 构建1年 2季度 3个月letcomplexPeriod::zero().y(1).q(2).m(3);assert_eq!(complex.as_months(),1263);// 21个月设计优势类型安全通过类型系统区分时段和普通整数避免混淆语义清晰使用年/月/季度等业务术语代码自解释运算完备支持加减乘除和求和方便批量计算不可变性所有方法返回新实例保证线程安全计划友好专为计划场景设计不涉及不精确的日单位适用场景项目计划与排期合同期限管理投资周期计算里程碑规划任何需要以年/月为单位进行粗略时间计算的场景不适用场景需要精确到天的时间计算跨时区时间处理需要考虑闰年、月份天数差异的场景需要锚定具体日期的时间运算完整代码// // period.rs// //! 粗略时段Periodusestd::ops::{Add,Sub,Mul,Div,Neg};// 常量 constMONTHS_PER_YEAR:i6412;constMONTHS_PER_QUARTER:i643;/// 粗略时段以年、月为单位的计划性时间长度////// - 仅用于计划场景如3个月后交付/// - 可正可负/// - ❌ 不混入日或更小单位无锚定时无意义#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]pubstructPeriod{pub(crate)months:i64,}implPeriod{// 构造方法 pubconstfnfrom_months(months:i64)-Self{Self{months}}pubconstfnfrom_years(years:i64)-Self{Self{months:years*MONTHS_PER_YEAR}}pubconstfnfrom_quarters(quarters:i64)-Self{Self{months:quarters*MONTHS_PER_QUARTER}}pubconstfnzero()-Self{Self{months:0}}// 视图方法 pubconstfnas_months(self)-i64{self.months}pubconstfnis_zero(self)-bool{self.months0}pubconstfnis_positive(self)-bool{self.months0}pubconstfnis_negative(self)-bool{self.months0}pubconstfnas_years(self)-i64{self.months.div_euclid(MONTHS_PER_YEAR)}pubconstfnas_quarters(self)-i64{self.months.div_euclid(MONTHS_PER_QUARTER)}pubconstfnremaining_months_after_quarters(self)-i64{self.months.rem_euclid(MONTHS_PER_QUARTER)}pubconstfnremaining_months(self)-i64{self.months.rem_euclid(MONTHS_PER_YEAR)}pubconstfnabs(self)-Self{Self{months:self.months.abs()}}// 链式方法 pubconstfnm(mutself,months:i64)-Self{self.monthsmonths;self}pubconstfny(mutself,years:i64)-Self{self.monthsyears*MONTHS_PER_YEAR;self}pubconstfnq(mutself,quarters:i64)-Self{self.monthsquarters*MONTHS_PER_QUARTER;self}}// 运算符重载 implAddforPeriod{typeOutputSelf;fnadd(self,rhs:Self)-Self{Self{months:self.monthsrhs.months}}}implSubforPeriod{typeOutputSelf;fnsub(self,rhs:Self)-Self{Self{months:self.months-rhs.months}}}implNegforPeriod{typeOutputSelf;fnneg(self)-Self{Self{months:-self.months}}}implMuli64forPeriod{typeOutputSelf;fnmul(self,rhs:i64)-Self{Self{months:self.months*rhs}}}implDivi64forPeriod{typeOutputSelf;fndiv(self,rhs:i64)-Self{Self{months:self.months.div_euclid(rhs)}}}implstd::iter::SumforPeriod{fnsumI:IteratorItemSelf(iter:I)-Self{iter.fold(Period::zero(),|acc,p|accp)}}implastd::iter::SumaPeriodforPeriod{fnsumI:IteratorItemaPeriod(iter:I)-Self{iter.fold(Period::zero(),|acc,p|acc*p)}}// // 测试// #[cfg(test)]modtests{usesuper::*;#[test]fntest_construction(){assert_eq!(Period::from_months(6).as_months(),6);assert_eq!(Period::from_years(1).as_months(),12);assert_eq!(Period::from_quarters(2).as_months(),6);assert_eq!(Period::zero().as_months(),0);}#[test]fntest_chain(){letpPeriod::from_months(1).m(2).y(1).q(1);// 1 2 12 3 18assert_eq!(p.as_months(),18);}#[test]fntest_as_methods(){letpPeriod::from_months(13);assert_eq!(p.as_years(),1);assert_eq!(p.as_quarters(),4);assert_eq!(p.remaining_months_after_quarters(),1);assert_eq!(p.remaining_months(),1);// 负数向下取整letpPeriod::from_months(-13);assert_eq!(p.as_years(),-2);assert_eq!(p.as_quarters(),-5);assert_eq!(p.remaining_months_after_quarters(),2);assert_eq!(p.remaining_months(),11);}#[test]fntest_operators(){letp1Period::from_months(3);letp2Period::from_months(5);assert_eq!((p1p2).as_months(),8);assert_eq!((p2-p1).as_months(),2);assert_eq!((p1*2).as_months(),6);assert_eq!((p2/2).as_months(),2);assert_eq!((-p1).as_months(),-3);}#[test]fntest_abs(){letpPeriod::from_months(-3);assert_eq!(p.abs().as_months(),3);}#[test]fntest_is_zero_positive_negative(){assert!(Period::zero().is_zero());assert!(Period::from_months(1).is_positive());assert!(Period::from_months(-1).is_negative());}#[test]fntest_sum(){letperiodsvec![Period::from_months(1),Period::from_months(2),Period::from_months(3),];lettotal:Periodperiods.iter().sum();assert_eq!(total.as_months(),6);lettotal:Periodperiods.into_iter().sum();assert_eq!(total.as_months(),6);}}