我正在尝试实现一个表示日期的结构,可以使用范围语法(for d in start..end { }
)。我知道已经存在处理日期的板条箱,但我这样做是为了练习。
这是结构:
type DayOfMonth = u8;
type Month = u8;
type Year = u16;
#[derive(PartialEq, Eq, Clone)]
pub struct Date {
pub year: Year,
pub month: Month,
pub day: DayOfMonth
}
以下是我想要使用它的方法:
fn print_dates() {
let start = Date { year: 1999, month: 1, day: 1 };
let end = Date { year: 1999, month: 12, day: 31 };
for d in start..end {
println!("{}-{}-{}", d.year, d.month, d.day);
}
}
我最初尝试实现Iterator
特性,但是当我尝试使用范围语法时,我收到编译错误,说我需要实现Step
。
文档显示Step
特征的此签名。
pub trait Step: PartialOrd<Self> + Clone {
fn steps_between(start: &Self, end: &Self) -> Option<usize>;
fn replace_one(&mut self) -> Self;
fn replace_zero(&mut self) -> Self;
fn add_one(&self) -> Self;
fn sub_one(&self) -> Self;
fn add_usize(&self, n: usize) -> Option<Self>;
}
我已经实施了Ord
和PartialOrd
:
impl Ord for Date {
fn cmp(&self, other: &Self) -> Ordering {
match self.year.cmp(&other.year) {
Ordering::Equal =>
match self.month.cmp(&other.month) {
Ordering::Equal =>
self.day.cmp(&other.day),
ord => ord
},
ord => ord
}
}
}
impl PartialOrd for Date {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
我正在使用Clone
自动实施#[derive(Clone)]
。
我开始实现Step
,但有一些方法我无法弄清楚该怎么做。以下是我到目前为止的情况:
impl Step for Date {
fn steps_between(start: &self, end: &self) -> Option<usize> {
//is_valid_date checks that the month is not > 12 and other rules like that
if is_valid_date(start) && is_valid_date(end) {
//get_epoch_day_number gets the number of days since 1900-01-01
let diff = get_epoch_day_number(end) - get_epoch_day_number(start);
Some(diff)
}
else { None }
}
fn add_one(&self) -> Self {
//Try the next day
let mut next = Date {
year: self.year,
month: self.month,
day: self.day + 1
};
//If not valid, try the 1st of the next month
if !is_valid_date(&next) {
next = Date {
year: self.year,
month: self.month + 1,
day: 1
};
}
//If not valid, try the 1st of the next year
if !is_valid_date(&next) {
next = Date {
year: self.year + 1,
month: 1,
day: 1
};
}
next
}
fn sub_one(&self) -> Self {
//Try the prev day
let mut prev = Date {
year: self.year,
month: self.month,
day: self.day - 1
};
//If not valid, try the last of the prev month
if !is_valid_date(&prev) {
let m = self.month - 1;
prev = Date {
year: self.year,
month: m,
day: get_month_length(self.year, m)
};
}
//If not valid, try the last of the prev year
if !is_valid_date(&prev) {
prev = Date {
year: self.year - 1,
month: 12,
day: 31
};
}
prev
}
fn add_usize(&self, n: usize) -> Self {
//This is really inefficient, but that's not important
let mut result = self;
for i in 1..n+1 {
result = result.add_one();
}
result
}
fn replace_one(&mut self) -> Self {
// ?
}
fn replace_zero(&mut self) -> Self {
// ?
}
}
我对replace_one
和replace_zero
应该做的事情感到非常难过。文档说:
用1
替换此步骤,返回自身。和用0
替换此步骤,返回自身。
我的结构体是否需要zero
和one
标识值才能在范围内使用? add_one
不应该足够吗?
文档中使用的措辞也有点不清楚。如果我们将x
替换为1
并返回“本身”,那么“是”x
还是1
?
答案 0 :(得分:1)
我只是看了Rust的代码,其中使用了这些方法。 The only uses in whole of rustc's repository将实施RangeInclusive
次操作。空RangeInclusive
表示为从1
到0
的范围,因此next
,next_back
和nth
方法需要能够以某种方式得到这些,这就是replace_one
和replace_zero
的用途。
我建议在rustc的GitHub上打开一个问题,以使文档更好,并可能更改这些方法的名称。