rust
// 基本定义
#[repr(u8)]
pub enum Month {
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,这符合日常习惯:
rust
#[repr(u8)] // 确保以 u8 形式存储
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Month {
January = 1, // 不是 0!
// ... 其他月份
December = 12,
}
2. 核心方法实现
2.1 创建和转换方法
rust
impl Month {
/// 从数字创建月份
pub(crate) const fn from_number(n: NonZero<u8>) -> Result<Self, error::ComponentRange> {
match n.get() {
1 => Ok(January),
// ... 2-11
12 => Ok(December),
n => Err(error::ComponentRange { /* 错误详情 */ }),
}
}
/// 获取月份天数(考虑闰年)
pub const fn length(self, year: i32) -> u8 {
util::days_in_month(self, year)
}
}
2.2 月份导航方法
rust
impl Month {
/// 获取上个月
pub const fn previous(self) -> Self {
match self {
January => December,
February => January,
// ... 其他匹配
}
}
/// 获取下个月
pub const fn next(self) -> Self {
match self {
January => February,
// ... 其他匹配
December => January,
}
}
/// 获取第 n 个下个月
pub const fn nth_next(self, n: u8) -> Self {
match (self as u8 - 1 + n % 12) % 12 {
0 => January,
// ... 1-10
11 => December,
_ => unreachable!(),
}
}
}
3. 特性实现
3.1 智能显示(SmartDisplay)
rust
impl SmartDisplay for Month {
type Metadata = MonthMetadata;
fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
match self {
January => Metadata::new(7, self, MonthMetadata), // "January" 长度 7
February => Metadata::new(8, self, MonthMetadata), // "February" 长度 8
// ... 其他月份
}
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad(match self {
January => "January",
// ... 其他月份名称
})
}
}
3.2 标准特性实现
rust
// 显示实现委托给 SmartDisplay
impl fmt::Display for Month {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
SmartDisplay::fmt(self, f)
}
}
// 从字符串解析
impl FromStr for Month {
type Err = error::InvalidVariant;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"January" => Ok(January),
// ... 其他月份名称
_ => Err(error::InvalidVariant),
}
}
}
3.3 类型转换
rust
// Month -> u8
impl From<Month> for u8 {
fn from(month: Month) -> Self {
month as Self // 安全:月份值 1-12
}
}
// u8 -> Month(安全转换)
impl TryFrom<u8> for Month {
type Error = error::ComponentRange;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match NonZero::new(value) {
Some(value) => Self::from_number(value),
None => Err(/* 错误:值为 0 */),
}
}
}
4. 设计特点总结
| 特点 | 说明 |
|---|---|
| 类型安全 | 使用枚举而非整数,防止无效月份值 |
| 零成本抽象 | 使用 const 函数和内联优化 |
| 内存优化 | 使用 NonZero<u8> 和 #[repr(u8)] |
| 完整功能 | 支持显示、解析、导航、天数计算 |
| 实用 API | 提供日常需要的月份操作 |
5. 使用示例
rust
// 创建月份
let january = Month::January;
let february = Month::try_from(2).unwrap();
// 显示月份
println!("Current month: {}", january); // "January"
// 计算天数(考虑闰年)
println!("Days in Feb 2020: {}", Month::February.length(2020)); // 29
// 月份导航
let next_month = january.next(); // February
let three_months_later = january.nth_next(3); // April
// 类型转换
let month_num: u8 = january.into(); // 1
let from_str: Month = "March".parse().unwrap(); // Month::March