Rust Exercism 练习系列详解(Anagram、Space Age、Sublist)
大家好,我是 小杍随笔 。最近在刷 Exercism Rust Track 时,遇到了几个经典练习:Anagram(变位词) 、Space Age(行星年龄) 和 Sublist(子列表判断) 。这些练习分别考察了 生命周期(lifetimes) 、trait 默认实现 + 宏 、枚举 + 模式匹配 + windows API 等 Rust 核心特性。
下面我把我们讨论的过程、代码实现和详细解读整理成一篇,供大家参考。
1. Anagram(变位词判断)
练习要求:给定一个目标词和若干候选词,找出所有是目标词变位词(anagram)的候选词。忽略大小写,不把单词自身视为变位词,支持 Unicode。
关键点:
- 需要调整函数签名中的生命周期
- 使用小写 + 排序判断字母组成是否相同
完整实现:
rust
use std::collections::HashSet;
fn normalize(s: &str) -> Vec<char> {
let mut chars: Vec<char> = s.to_lowercase().collect();
chars.sort_unstable();
chars
}
pub fn anagrams_for<'a>(word: &str, possible_anagrams: &[&'a str]) -> HashSet<&'a str> {
let word_norm = normalize(word);
possible_anagrams
.iter()
.filter(|&&candidate| {
// 排除自身(忽略大小写)
if candidate.to_lowercase() == word.to_lowercase() {
return false;
}
normalize(candidate) == word_norm
})
.copied()
.collect()
}
解读 :normalize 函数把字符串转为小写字符并排序,是判断变位词最简洁高效的方式。生命周期 'a 确保返回的引用与输入候选词生命周期一致。
2. Space Age(行星年龄计算)
练习要求:给定秒数,计算在不同行星上相当于多少年(每个行星轨道周期不同)。
关键点:
From<u64>实现Planettrait 为每个行星实现years_during
推荐实现(清晰版):
rust
#[derive(Debug)]
pub struct Duration {
seconds: u64,
}
const SECONDS_PER_EARTH_YEAR: u64 = 31_557_600;
const MERCURY: f64 = 0.2408467;
const VENUS: f64 = 0.61519726;
const EARTH: f64 = 1.0;
const MARS: f64 = 1.8808158;
const JUPITER: f64 = 11.862615;
const SATURN: f64 = 29.447498;
const URANUS: f64 = 84.016846;
const NEPTUNE: f64 = 164.79132;
impl From<u64> for Duration {
fn from(s: u64) -> Self {
Duration { seconds: s }
}
}
pub trait Planet {
fn years_during(d: &Duration) -> f64;
}
pub struct Mercury;
impl Planet for Mercury {
fn years_during(d: &Duration) -> f64 {
d.seconds as f64 / SECONDS_PER_EARTH_YEAR as f64 / MERCURY
}
}
// Venus、Earth、Mars、Jupiter、Saturn、Uranus、Neptune 同理实现...
计算公式 :
行星年数 = (秒数 ÷ 地球年秒数) ÷ 该行星轨道周期(地球年)
优化建议 :可以使用 macro_rules! 消除重复代码,或者用关联常量 + 默认实现让代码更 DRY。
3. Sublist(子列表 / 超列表判断)
练习要求:判断两个列表的关系:
- Equal(完全相等)
- Sublist(第一个是第二个的子列表)
- Superlist(第一个是第二个的超列表)
- Unequal(以上均不成立)
核心函数解读:
rust
fn is_sublist(needle: &[i32], haystack: &[i32]) -> bool {
if needle.len() > haystack.len() {
return false;
}
haystack.windows(needle.len()).any(|w| w == needle)
}
详细解读:
haystack.windows(needle.len()):滑动窗口 API,返回大列表中所有长度等于needle的连续子切片 。- 例如 haystack =
[1,2,3,4],needle.len()=2 时,会产生[1,2]、[2,3]、[3,4]。
- 例如 haystack =
.any(|w| w == needle):只要有一个窗口与 needle 完全相等,就返回true。
这是 Rust 中判断连续子列表的最优雅写法,零成本、高性能。
完整 sublist 函数(推荐现代写法):
rust
#[derive(Debug, PartialEq, Eq)]
pub enum Comparison {
Equal,
Sublist,
Superlist,
Unequal,
}
pub fn sublist(first_list: &[i32], second_list: &[i32]) -> Comparison {
if first_list.is_empty() && second_list.is_empty() {
return Comparison::Equal;
}
if first_list.is_empty() {
return Comparison::Sublist;
}
if second_list.is_empty() {
return Comparison::Superlist;
}
match first_list.len().cmp(&second_list.len()) {
std::cmp::Ordering::Equal => {
if first_list == second_list {
Comparison::Equal
} else {
Comparison::Unequal
}
}
std::cmp::Ordering::Less => {
if is_sublist(first_list, second_list) {
Comparison::Sublist
} else {
Comparison::Unequal
}
}
std::cmp::Ordering::Greater => {
if is_sublist(second_list, first_list) {
Comparison::Superlist
} else {
Comparison::Unequal
}
}
}
}
match 表达式解读 :
first_list.len().cmp(&second_list.len()) 返回 Ordering::Equal / Less / Greater,用于快速分流逻辑,避免不必要的检查。
总结与建议
- Anagram 重点掌握生命周期和字符串规范化。
- Space Age 练习 trait 默认实现、常量提取和代码去重(宏或关联常量)。
- Sublist 是 Rust 迭代器和模式匹配的经典案例,
windows()+any()是必学技巧。
这些练习难度适中,但覆盖了 Rust 很多重要概念。建议多读官方文档中关于 lifetimes 、traits 、iterators 的章节。
文章标签 :
Rust、Exercism、Rust 练习、生命周期、Trait、Sublist、Anagram、Space Age、Rust 入门