当前位置: 首页 > news >正文

Rust 练习册 :Proverb与字符串处理

“Proverb”(谚语)练习源自一句经典的英文谚语:“For want of a nail the shoe was lost”,表达了一个小小的缺失可能导致连锁反应,最终造成重大损失的道理。在 Exercism 的 “proverb” 练习中,我们需要根据给定的词汇列表生成这个谚语的完整形式。这不仅能帮助我们掌握字符串处理和迭代器操作技巧,还能深入学习Rust中的字符串拼接、模式匹配和函数式编程。

什么是 Proverb 谚语?

“For want of a nail” 是一个经典的英语谚语,用来说明小问题如何引发连锁反应导致大问题。完整的谚语形式如下:

For want of a nail the shoe was lost.
For want of a shoe the horse was lost.
For want of a horse the rider was lost.
For want of a rider the battle was lost.
For want of a battle the kingdom was lost.
And all for the want of a nail.

这个谚语说明了因为缺少一个钉子,最终导致整个王国的沦陷,强调了细节的重要性。

让我们先看看练习提供的函数实现:

pub fn build_proverb(list: &[&str]) -> String {if list.is_empty() {return String::new();}let res = list.windows(2).map(|x| format!("For want of a {} the {} was lost.", x[0], x[1])).chain(std::iter::once(format!("And all for the want of a {}.",list[0]))).collect::<Vec<_>>();res.join("\n")
}

这是一个使用Rust迭代器链的优雅实现,通过[windows](file:///Users/zacksleo/projects/github/zacksleo/exercism-rust/exercises/practice/docs/rust-exercise-62-proverb.md#struct.Windows)方法创建相邻元素对,然后使用[map](file:///Users/zacksleo/projects/github/zacksleo/exercism-rust/exercises/practice/docs/rust-exercise-62-proverb.md#impl-IoSlice.pub%20const%20fn%20new(buf:%20%27a%20[u8])%20->%20IoSlice%27a_)转换为谚语句子,最后添加总结句。

设计分析

1. 核心要求

  1. 字符串格式化:正确格式化谚语句子
  2. 相邻元素处理:处理列表中相邻的元素对
  3. 总结句生成:生成总结性的最后一句
  4. 边界处理:正确处理空列表和单元素列表

2. 技术要点

  1. 迭代器链:使用Rust强大的迭代器功能
  2. 字符串拼接:高效地拼接多行字符串
  3. 模式匹配:处理不同的输入情况
  4. 函数式编程:使用函数式方法处理数据转换

完整实现

1. 基础迭代器实现

pub fn build_proverb(list: &[&str]) -> String {if list.is_empty() {return String::new();}let res = list.windows(2).map(|x| format!("For want of a {} the {} was lost.", x[0], x[1])).chain(std::iter::once(format!("And all for the want of a {}.",list[0]))).collect::<Vec<_>>();res.join("\n")
}

2. 使用String.push_str的实现

pub fn build_proverb(list: &[&str]) -> String {if list.is_empty() {return String::new();}if list.len() == 1 {return format!("And all for the want of a {}.", list[0]);}let mut result = String::new();// 生成中间句子for i in 0..list.len() - 1 {if !result.is_empty() {result.push('\n');}result.push_str(&format!("For want of a {} the {} was lost.", list[i], list[i + 1]));}// 添加总结句result.push('\n');result.push_str(&format!("And all for the want of a {}.", list[0]));result
}

3. 使用fold的函数式实现

pub fn build_proverb(list: &[&str]) -> String {if list.is_empty() {return String::new();}if list.len() == 1 {return format!("And all for the want of a {}.", list[0]);}let main_lines: Vec<String> = list.windows(2).map(|pair| format!("For want of a {} the {} was lost.", pair[0], pair[1])).collect();let summary_line = format!("And all for the want of a {}.", list[0]);main_lines.iter().chain(std::iter::once(&summary_line)).fold(String::new(), |acc, line| {if acc.is_empty() {line.clone()} else {acc + "\n" + line}})
}

测试用例分析

通过查看测试用例,我们可以更好地理解需求:

#[test]
fn test_two_pieces() {let input = vec!["nail", "shoe"];let expected = vec!["For want of a nail the shoe was lost.","And all for the want of a nail.",].join("\n");assert_eq!(build_proverb(&input), expected);
}

两个元素的列表应该生成一行主句和一行总结句。

#[test]
fn test_three_pieces() {let input = vec!["nail", "shoe", "horse"];let expected = vec!["For want of a nail the shoe was lost.","For want of a shoe the horse was lost.","And all for the want of a nail.",].join("\n");assert_eq!(build_proverb(&input), expected);
}

三个元素的列表应该生成两行主句和一行总结句。

#[test]
fn test_one_piece() {let input = vec!["nail"];let expected = String::from("And all for the want of a nail.");assert_eq!(build_proverb(&input), expected);
}

单个元素的列表应该只生成总结句。

#[test]
fn test_zero_pieces() {let input: Vec<&str> = vec![];let expected = String::new();assert_eq!(build_proverb(&input), expected);
}

空列表应该返回空字符串。

#[test]
fn test_full() {let input = vec!["nail", "shoe", "horse", "rider", "message", "battle", "kingdom",];let expected = vec!["For want of a nail the shoe was lost.","For want of a shoe the horse was lost.","For want of a horse the rider was lost.","For want of a rider the message was lost.","For want of a message the battle was lost.","For want of a battle the kingdom was lost.","And all for the want of a nail.",].join("\n");assert_eq!(build_proverb(&input), expected);
}

完整的谚语应该正确生成所有句子。

#[test]
fn test_three_pieces_modernized() {let input = vec!["pin", "gun", "soldier", "battle"];let expected = vec!["For want of a pin the gun was lost.","For want of a gun the soldier was lost.","For want of a soldier the battle was lost.","And all for the want of a pin.",].join("\n");assert_eq!(build_proverb(&input), expected);
}

不同的词汇列表也应该正确处理。

性能优化版本

考虑性能的优化实现:

pub fn build_proverb(list: &[&str]) -> String {if list.is_empty() {return String::new();}if list.len() == 1 {return format!("And all for the want of a {}.", list[0]);}// 预估结果字符串的容量以减少重新分配let estimated_capacity = list.iter().map(|s| s.len()).sum::<usize>() * 10 + list.len() * 50;let mut result = String::with_capacity(estimated_capacity);// 生成主句for window in list.windows(2) {if !result.is_empty() {result.push('\n');}result.push_str("For want of a ");result.push_str(window[0]);result.push_str(" the ");result.push_str(window[1]);result.push_str(" was lost.");}// 添加总结句result.push('\n');result.push_str("And all for the want of a ");result.push_str(list[0]);result.push('.');result
}// 使用格式化参数的版本
pub fn build_proverb_formatted(list: &[&str]) -> String {if list.is_empty() {return String::new();}if list.len() == 1 {return format!("And all for the want of a {}.", list[0]);}let mut lines: Vec<String> = Vec::with_capacity(list.len());// 生成主句for window in list.windows(2) {lines.push(format!("For want of a {} the {} was lost.", window[0], window[1]));}// 添加总结句lines.push(format!("And all for the want of a {}.", list[0]));lines.join("\n")
}// 使用write!宏的版本
use std::fmt::Write;pub fn build_proverb_write(list: &[&str]) -> String {if list.is_empty() {return String::new();}let mut result = String::new();// 生成主句for window in list.windows(2) {if !result.is_empty() {result.push('\n');}write!(result, "For want of a {} the {} was lost.", window[0], window[1]).expect("Failed to write to string");}// 添加总结句if !list.windows(2).count() > 0 {result.push('\n');}write!(result, "And all for the want of a {}.", list[0]).expect("Failed to write to string");result
}

错误处理和边界情况

考虑更多边界情况的实现:

pub fn build_proverb(list: &[&str]) -> String {// 处理空列表if list.is_empty() {return String::new();}// 处理只包含空字符串的列表if list.iter().all(|&s| s.is_empty()) {return String::new();}// 过滤掉空字符串let non_empty_list: Vec<&str> = list.iter().filter(|&&s| !s.is_empty()).copied().collect();if non_empty_list.is_empty() {return String::new();}if non_empty_list.len() == 1 {return format!("And all for the want of a {}.", non_empty_list[0]);}let mut result = String::new();// 生成主句for window in non_empty_list.windows(2) {if !result.is_empty() {result.push('\n');}result.push_str(&format!("For want of a {} the {} was lost.", window[0], window[1]));}// 添加总结句result.push('\n');result.push_str(&format!("And all for the want of a {}.", non_empty_list[0]));result
}// 返回Result的版本
#[derive(Debug, PartialEq)]
pub enum ProverbError {EmptyList,EmptyWords,
}impl std::fmt::Display for ProverbError {fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {match self {ProverbError::EmptyList => write!(f, "列表为空"),ProverbError::EmptyWords => write!(f, "列表中包含空词汇"),}}
}impl std::error::Error for ProverbError {}pub fn build_proverb_safe(list: &[&str]) -> Result<String, ProverbError> {if list.is_empty() {return Err(ProverbError::EmptyList);}if list.iter().any(|&s| s.is_empty()) {return Err(ProverbError::EmptyWords);}Ok(build_proverb(list))
}// 支持自定义格式的版本
pub struct ProverbBuilder {prefix: String,suffix: String,separator: String,summary_prefix: String,summary_suffix: String,
}impl ProverbBuilder {pub fn new() -> Self {ProverbBuilder {prefix: "For want of a ".to_string(),suffix: " was lost.".to_string(),separator: " the ".to_string(),summary_prefix: "And all for the want of a ".to_string(),summary_suffix: ".".to_string(),}}pub fn with_prefix(mut self, prefix: &str) -> Self {self.prefix = prefix.to_string();self}pub fn with_suffix(mut self, suffix: &str) -> Self {self.suffix = suffix.to_string();self}pub fn with_separator(mut self, separator: &str) -> Self {self.separator = separator.to_string();self}pub fn with_summary_prefix(mut self, prefix: &str) -> Self {self.summary_prefix = prefix.to_string();self}pub fn with_summary_suffix(mut self, suffix: &str) -> Self {self.summary_suffix = suffix.to_string();self}pub fn build(&self, list: &[&str]) -> String {if list.is_empty() {return String::new();}if list.len() == 1 {return format!("{}{}{}", self.summary_prefix, list[0], self.summary_suffix);}let mut result = String::new();// 生成主句for window in list.windows(2) {if !result.is_empty() {result.push('\n');}result.push_str(&format!("{}{}{}{}{}", self.prefix, window[0], self.separator, window[1], self.suffix));}// 添加总结句result.push('\n');result.push_str(&format!("{}{}{}", self.summary_prefix, list[0], self.summary_suffix));result}
}

扩展功能

基于基础实现,我们可以添加更多功能:

pub struct Proverb {words: Vec<String>,
}impl Proverb {pub fn new(words: Vec<&str>) -> Self {Proverb {words: words.into_iter().map(|s| s.to_string()).collect(),}}pub fn build(&self) -> String {build_proverb(&self.words.iter().map(|s| s.as_str()).collect::<Vec<_>>())}// 获取词汇列表pub fn words(&self) -> &[String] {&self.words}// 添加词汇pub fn add_word(&mut self, word: &str) {self.words.push(word.to_string());}// 获取谚语行数pub fn line_count(&self) -> usize {if self.words.is_empty() {0} else {self.words.len()}}// 获取特定行pub fn line(&self, index: usize) -> Option<String> {if self.words.is_empty() {return None;}if index >= self.words.len() {return None;}if self.words.len() == 1 {return Some(format!("And all for the want of a {}.", self.words[0]));}if index == self.words.len() - 1 {// 最后一行是总结句Some(format!("And all for the want of a {}.", self.words[0]))} else if index < self.words.len() - 1 {// 中间行是主句Some(format!("For want of a {} the {} was lost.", self.words[index], self.words[index + 1]))} else {None}}// 反向构建谚语(从后往前)pub fn build_reverse(&self) -> String {if self.words.is_empty() {return String::new();}if self.words.len() == 1 {return format!("And all for the want of a {}.", self.words[0]);}let mut lines: Vec<String> = Vec::with_capacity(self.words.len());// 生成主句(反向)for i in (0..self.words.len() - 1).rev() {lines.push(format!("For want of a {} the {} was lost.", self.words[i + 1], self.words[i]));}// 添加总结句lines.push(format!("And all for the want of a {}.", self.words[self.words.len() - 1]));lines.join("\n")}
}// 谚语分析器
pub struct ProverbAnalysis {pub word_count: usize,pub line_count: usize,pub character_count: usize,pub first_word: Option<String>,pub last_word: Option<String>,
}impl Proverb {pub fn analyze(&self) -> ProverbAnalysis {let word_count = self.words.len();let line_count = self.line_count();let character_count = self.build().chars().count();let first_word = self.words.first().cloned();let last_word = self.words.last().cloned();ProverbAnalysis {word_count,line_count,character_count,first_word,last_word,}}
}// 多语言支持
pub struct MultiLanguageProverbBuilder {translations: std::collections::HashMap<&'static str, ProverbTemplate>,
}pub struct ProverbTemplate {line_template: String,          // "For want of a {} the {} was lost."summary_template: String,       // "And all for the want of a {}."
}impl MultiLanguageProverbBuilder {pub fn new() -> Self {let mut builder = MultiLanguageProverbBuilder {translations: std::collections::HashMap::new(),};// 添加英语模板builder.translations.insert("en", ProverbTemplate {line_template: "For want of a {} the {} was lost.".to_string(),summary_template: "And all for the want of a {}.".to_string(),});// 添加中文模板builder.translations.insert("zh", ProverbTemplate {line_template: "缺了{},{}就丢了。".to_string(),summary_template: "所有这些都因为缺了{}。".to_string(),});builder}pub fn build(&self, language: &str, words: &[&str]) -> Option<String> {let template = self.translations.get(language)?;if words.is_empty() {return Some(String::new());}if words.len() == 1 {return Some(template.summary_template.replace("{}", words[0]));}let mut lines: Vec<String> = Vec::with_capacity(words.len());// 生成主句for window in words.windows(2) {lines.push(template.line_template.replace("{}", window[0]).replace("{}", window[1]));}// 添加总结句lines.push(template.summary_template.replace("{}", words[0]));Some(lines.join("\n"))}
}// 便利函数
pub fn build_proverb(list: &[&str]) -> String {if list.is_empty() {return String::new();}let res = list.windows(2).map(|x| format!("For want of a {} the {} was lost.", x[0], x[1])).chain(std::iter::once(format!("And all for the want of a {}.",list[0]))).collect::<Vec<_>>();res.join("\n")
}pub fn format_proverb_with_numbering(list: &[&str]) -> String {let proverb = build_proverb(list);let lines: Vec<&str> = proverb.lines().collect();lines.iter().enumerate().map(|(i, line)| format!("{}. {}", i + 1, line)).collect::<Vec<_>>().join("\n")
}

实际应用场景

Proverb 谚语在实际开发中有以下应用:

  1. 教育软件:语言学习和文学教学工具
  2. 文本生成:自动生成有哲理的文本内容
  3. 游戏开发:益智游戏和文字游戏
  4. 演示工具:编程教学和示例演示
  5. 文化应用:谚语和格言展示应用
  6. 写作辅助:创意写作和内容生成工具
  7. 心理应用:正念练习和哲理思考工具
  8. 社交媒体:生成有深度的社交媒体内容

算法复杂度分析

  1. 时间复杂度:O(n×m)

    • 其中n是词汇列表长度,m是平均词汇长度
    • 需要遍历列表并生成每个句子
  2. 空间复杂度:O(n×m)

    • 需要存储生成的谚语字符串

与其他实现方式的比较

// 使用递归的实现
pub fn build_proverb_recursive(list: &[&str]) -> String {fn build_lines(words: &[&str], first_word: &str) -> Vec<String> {if words.len() < 2 {return vec![format!("And all for the want of a {}.", first_word)];}let mut lines = vec![format!("For want of a {} the {} was lost.", words[0], words[1])];lines.extend(build_lines(&words[1..], first_word));lines}if list.is_empty() {return String::new();}if list.len() == 1 {return format!("And all for the want of a {}.", list[0]);}build_lines(list, list[0]).join("\n")
}// 使用第三方库的实现
// [dependencies]
// itertools = "0.10"use itertools::Itertools;pub fn build_proverb_itertools(list: &[&str]) -> String {if list.is_empty() {return String::new();}let main_lines: Vec<String> = list.iter().tuple_windows().map(|(a, b)| format!("For want of a {} the {} was lost.", a, b)).collect();let summary_line = format!("And all for the want of a {}.", list[0]);main_lines.into_iter().chain(std::iter::once(summary_line)).join("\n")
}// 使用宏的实现
macro_rules! proverb {() => {String::new()};($first:expr) => {format!("And all for the want of a {}.", $first)};($first:expr, $($rest:expr),+) => {{let words = vec![$first, $($rest),+];build_proverb(&words)}};
}// 使用状态机的实现
#[derive(Debug, Clone)]
enum ProverbState {Start,Building { lines: Vec<String>, current_index: usize },Done { result: String },
}pub fn build_proverb_state_machine(list: &[&str]) -> String {if list.is_empty() {return String::new();}if list.len() == 1 {return format!("And all for the want of a {}.", list[0]);}let mut lines = Vec::new();// 生成主句for window in list.windows(2) {lines.push(format!("For want of a {} the {} was lost.", window[0], window[1]));}// 添加总结句lines.push(format!("And all for the want of a {}.", list[0]));lines.join("\n")
}

总结

通过 proverb 练习,我们学到了:

  1. 字符串处理:掌握了Rust中字符串处理和格式化技巧
  2. 迭代器使用:深入理解了Rust迭代器链的强大功能
  3. 函数式编程:学会了使用函数式方法处理数据转换
  4. 边界处理:理解了如何处理各种边界情况
  5. 性能优化:学会了预分配内存和使用高效算法等优化技巧
  6. 设计模式:理解了构建者模式和模板方法的应用

这些技能在实际开发中非常有用,特别是在文本处理、内容生成、教育软件等场景中。Proverb练习虽然是一个简单的文本生成问题,但它涉及到了字符串处理、迭代器使用、函数式编程、边界处理等许多核心概念,是学习Rust实用编程的良好起点。

通过这个练习,我们也看到了Rust在文本处理和字符串操作方面的强大能力,以及如何用安全且高效的方式实现文本生成算法。这种结合了安全性和性能的语言特性正是Rust的魅力所在。

http://www.dtcms.com/a/585692.html

相关文章:

  • 做国际贸易需要网站吗关键词优化排名费用
  • SpringBoot 集成 RabbitMQ
  • 有做公司网站潍坊关键词优化软件
  • Linux 管道(pipe/FIFO)全指南:概念、语义、原子性、阻塞规则、实战代码与最佳实践
  • Servlet的基本使用和作用
  • openEuler上安装高版本的docker
  • 【办公类-123-02】20251108AI照片合成《证件照蝴蝶结》
  • PostgreSQL SELECT 语句详解
  • 16_FastMCP 2.x 中文文档之FastMCP服务端高级功能:代理服务器详解
  • 住房住房和城乡建设部网站首页网络营销的特点与优势
  • 免费公司网站模板站长工具seo查询5g5g
  • AI黑客来袭:Strix如何用大模型重新定义渗透测试游戏规则
  • 系统规划与管理师学习--论文case
  • linux部署confluence7.19.7
  • 工业视觉中的白平衡,为何是色彩准确性的基石
  • Delphi跨平台开发中为Linux开发的优劣分析
  • 凡科网站源码下载做零售外贸网站有哪些
  • KVStore 多行文章型键值扩展解析:切片存储与客户端多行交互
  • 【PLM实施专家宝典】离散制造企业MBD与无纸化制造实施方案:从“图纸驱动”到“数据驱动”的革命
  • 手机网站关键词排名查询wordpress响应式播放器
  • 在Linux系统中图形化显示GPU显存利用率的软件
  • 大数据成矿预测系列(八) | 从定性到概率:逻辑回归——地质统计学派的“集大成者”
  • 微网站搭建教程网站如何建设移动端
  • JS前端性能优化实战指南:从首屏加载到运行时流畅,构建高性能应用
  • stringRedisTemplate.opsForHash().entries
  • 深圳做自适应网站网站开发案例教程
  • 做网站需要注册公司吗360网站安全在线检测
  • node_exporter安装
  • 解读USCAR-2-7-2020
  • 日志消息的输出及落地