// 基本定义#[repr(u8)]pubenumMonth{January=1,February=2,March=3,April=4,May=5,June=6,July=7,August=8,September=9,October=10,November=11,December=12,}1. 枚举定义和特征
月份枚举从1开始编号而不是 0,这符合日常习惯:
#[repr(u8)]// 确保以 u8 形式存储#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]pubenumMonth{January=1,// 不是 0!// ... 其他月份December=12,}2. 核心方法实现
2.1 创建和转换方法
implMonth{/// 从数字创建月份pub(crate)constfnfrom_number(n:NonZero<u8>)->Result<Self,error::ComponentRange>{matchn.get(){1=>Ok(January),// ... 2-1112=>Ok(December),n=>Err(error::ComponentRange{/* 错误详情 */}),}}/// 获取月份天数(考虑闰年)pubconstfnlength(self,year:i32)->u8{util::days_in_month(self,year)}}2.2 月份导航方法
implMonth{/// 获取上个月pubconstfnprevious(self)->Self{matchself{January=>December,February=>January,// ... 其他匹配}}/// 获取下个月pubconstfnnext(self)->Self{matchself{January=>February,// ... 其他匹配December=>January,}}/// 获取第 n 个下个月pubconstfnnth_next(self,n:u8)->Self{match(selfasu8-1+n%12)%12{0=>January,// ... 1-1011=>December,_=>unreachable!(),}}}3. 特性实现
3.1 智能显示(SmartDisplay)
implSmartDisplayforMonth{typeMetadata=MonthMetadata;fnmetadata(&self,_:FormatterOptions)->Metadata<'_,Self>{matchself{January=>Metadata::new(7,self,MonthMetadata),// "January" 长度 7February=>Metadata::new(8,self,MonthMetadata),// "February" 长度 8// ... 其他月份}}fnfmt(&self,f:&mutfmt::Formatter<'_>)->fmt::Result{f.pad(matchself{January=>"January",// ... 其他月份名称})}}3.2 标准特性实现
// 显示实现委托给 SmartDisplayimplfmt::DisplayforMonth{fnfmt(&self,f:&mutfmt::Formatter<'_>)->fmt::Result{SmartDisplay::fmt(self,f)}}// 从字符串解析implFromStrforMonth{typeErr=error::InvalidVariant;fnfrom_str(s:&str)->Result<Self,Self::Err>{matchs{"January"=>Ok(January),// ... 其他月份名称_=>Err(error::InvalidVariant),}}}3.3 类型转换
// Month -> u8implFrom<Month>foru8{fnfrom(month:Month)->Self{monthasSelf// 安全:月份值 1-12}}// u8 -> Month(安全转换)implTryFrom<u8>forMonth{typeError=error::ComponentRange;fntry_from(value:u8)->Result<Self,Self::Error>{matchNonZero::new(value){Some(value)=>Self::from_number(value),None=>Err(/* 错误:值为 0 */),}}}4. 设计特点总结
| 特点 | 说明 |
|---|---|
| 类型安全 | 使用枚举而非整数,防止无效月份值 |
| 零成本抽象 | 使用const函数和内联优化 |
| 内存优化 | 使用NonZero<u8>和#[repr(u8)] |
| 完整功能 | 支持显示、解析、导航、天数计算 |
| 实用 API | 提供日常需要的月份操作 |
5. 使用示例
// 创建月份letjanuary=Month::January;letfebruary=Month::try_from(2).unwrap();// 显示月份println!("Current month: {}",january);// "January"// 计算天数(考虑闰年)println!("Days in Feb 2020: {}",Month::February.length(2020));// 29// 月份导航letnext_month=january.next();// Februaryletthree_months_later=january.nth_next(3);// April// 类型转换letmonth_num:u8=january.into();// 1letfrom_str:Month="March".parse().unwrap();// Month::March