代码初体验
在正式学习语法之前,我们先来跑一个真正”有用”的程序,感受一下 Rust 代码长什么样。
你的目标很简单:输入一个日期(年/月/日),程序告诉你那天是星期几。
你不需要现在看懂每一行——就像第一次坐飞机,你不必先学会造飞机。先上去飞一圈,感受一下。
完整程序
下面是一个能运行的完整程序。点击”运行”看看结果,然后我们再一起扫一眼代码结构。
// 判断是否是闰年
fn is_leap_year(year: u32) -> bool {
(year % 4 == 0 && year % 100 != 0) || year % 400 == 0
}
// 返回某月有多少天
fn days_in_month(year: u32, month: u32) -> u32 {
match month {
1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
4 | 6 | 9 | 11 => 30,
2 => if is_leap_year(year) { 29 } else { 28 },
_ => 0,
}
}
// 计算星期几
// 基准:1583年1月1日是星期六(格里历正式实施的第一年元旦)
fn day_of_week(year: u32, month: u32, day: u32) -> &'static str {
let weekdays = ["日", "一", "二", "三", "四", "五", "六"];
let mut total_days: u32 = 0;
// 累加 1583 年到目标年之前的天数
for y in 1583..year {
total_days += if is_leap_year(y) { 366 } else { 365 };
}
// 累加目标年内各月的天数
for m in 1..month {
total_days += days_in_month(year, m);
}
// 加上当月已过的天数(第1天不额外加)
total_days += day - 1;
// 1583-01-01 是星期六(索引 6),推算目标日期
let index = (total_days + 6) % 7;
weekdays[index as usize]
}
fn main() {
// 几个有意思的日期
let dates = [
(1583, 1, 1, "1583年元旦(格里历元年)"),
(1776, 7, 4, "美国独立宣言签署"),
(1969, 7, 20, "阿波罗11号登月"),
(2008, 8, 8, "北京奥运会开幕"),
(2024, 1, 1, "2024年元旦"),
];
println!("{:<24} 星期", "日期");
println!("{}", "─".repeat(30));
for (year, month, day, label) in dates {
let w = day_of_week(year, month, day);
println!("{:<24} 星期{}", label, w);
}
}为什么从 1583 年起? 1582 年之前,欧洲使用的是儒略历(Julian calendar),它的闰年规则比较简单(每 4 年一闰),但长期积累了误差——到 16 世纪末,历法已经比天文实际多走了约 10 天,导致春分节气漂移,影响复活节的计算。
1582 年,罗马教皇格里高利十三世推行格里历(Gregorian calendar,即今天全球通用的公历):规定整百年只有被 400 整除才算闰年(如 1600、2000 是闰年,而 1700、1800、1900 不是)。为了弥补历史误差,改历时直接删掉了 10 天——1582 年 10 月 4 日(星期四)的第二天变成了 10 月 15 日(星期五),中间 10 天在历史上消失了。
本程序使用格里历规则,从格里历正式生效的 1583 年 1 月 1 日起均可正确计算。
代码结构速览
不用现在记住语法细节,只看整体骨架:
fn is_leap_year(...) → 一个函数:判断闰年
fn days_in_month(...) → 一个函数:返回月份天数
fn day_of_week(...) → 一个函数:返回"一"/"二"/...
fn main() → 程序入口:调用上面的函数,打印结果
你能注意到的 Rust 特点:
fn开头定义函数(function 的缩写)//是注释,编译器忽略match类似其他语言的switch,但更强大for y in 1583..year是循环,从 1583 数到 yearlet声明变量,let mut声明可修改的变量
这些语法在后续章节里都会逐一讲清楚。现在只需要知道代码可以拆成一个个小函数,每个函数只做一件事——这是好代码的基本样子。
你来试试
算算你的生日
把下面代码里的日期改成你的生日或者今天,运行看看是哪天。
fn is_leap_year(year: u32) -> bool {
(year % 4 == 0 && year % 100 != 0) || year % 400 == 0
}
fn days_in_month(year: u32, month: u32) -> u32 {
match month {
1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
4 | 6 | 9 | 11 => 30,
2 => if is_leap_year(year) { 29 } else { 28 },
_ => 0,
}
}
fn day_of_week(year: u32, month: u32, day: u32) -> &'static str {
let weekdays = ["日", "一", "二", "三", "四", "五", "六"];
let mut total_days: u32 = 0;
for y in 1583..year {
total_days += if is_leap_year(y) { 366 } else { 365 };
}
for m in 1..month {
total_days += days_in_month(year, m);
}
total_days += day - 1;
weekdays[((total_days + 6) % 7) as usize]
}
fn main() {
// 把这里改成你的生日 ↓
let (year, month, day) = (2024, 1, 1);
println!(
"{}年{}月{}日 是 星期{}",
year, month, day,
day_of_week(year, month, day)
);
}用手机日历验证一下——结果对吗?
适用范围:1583 年及之后的日期均可使用。修改
(year, month, day) = (...)那一行即可。