"添加第3章类型系统实战内容,包含Option/Result、泛型、trait等示例和文件处理工具库实现"

This commit is contained in:
程广 2025-07-02 18:33:39 +08:00
parent 0b1fc76e73
commit d3437f021e
8 changed files with 1193 additions and 1 deletions

390
03.md Normal file
View File

@ -0,0 +1,390 @@
# 第3章 类型系统实战
> 本章要点类型系统基础、Option/Result、泛型、trait、错误处理
## 3.1 类型系统概述
Rust的类型系统是其最强大的特性之一它在编译时就能捕获大量潜在的错误。让我们深入了解Rust类型系统的核心特性。
### 3.1.1 Rust类型系统特点
Rust的类型系统具有以下关键特点
1. **静态类型**:所有变量在编译时都必须有明确的类型
2. **强类型**:类型之间没有隐式转换
3. **类型推断**:在大多数情况下编译器可以推断出类型
4. **零成本抽象**:类型系统的抽象在运行时没有性能开销
示例:类型推断与显式类型标注
```rust
// 类型推断
let x = 42; // 编译器推断为 i32
let y = 3.14; // 编译器推断为 f64
// 显式类型标注
let x: i32 = 42;
let y: f64 = 3.14;
```
### 3.1.2 类型安全保证
Rust的类型系统提供了强大的安全保证
1. **内存安全**:通过所有权系统防止内存泄漏和数据竞争
2. **空值安全**使用Option枚举代替null
3. **线程安全**通过Send和Sync trait保证
4. **错误处理**使用Result类型强制错误处理
## 3.2 Option和Result实战
### 3.2.1 Option枚举详解
Option是Rust处理可能为空值的标准方式
```rust
enum Option<T> {
Some(T),
None,
}
// Option使用示例
fn find_user(id: i32) -> Option<String> {
if id > 0 {
Some(String::from("User found"))
} else {
None
}
}
// 模式匹配处理Option
match find_user(1) {
Some(user) => println!("找到用户: {}", user),
None => println!("用户不存在"),
}
```
### 3.2.2 模式匹配最佳实践
模式匹配是处理Option和Result的强大工具
```rust
let maybe_value = Some(42);
// 1. match表达式
match maybe_value {
Some(value) => println!("值是: {}", value),
None => println!("没有值"),
}
// 2. if let语法
if let Some(value) = maybe_value {
println!("值是: {}", value);
}
// 3. while let循环
let mut stack = Vec::new();
stack.push(1);
stack.push(2);
while let Some(top) = stack.pop() {
println!("栈顶值: {}", top);
}
```
### 3.2.3 Result错误处理模式
Result用于处理可能失败的操作
```rust
enum Result<T, E> {
Ok(T),
Err(E),
}
// Result使用示例
fn divide(x: f64, y: f64) -> Result<f64, String> {
if y == 0.0 {
Err(String::from("除数不能为零"))
} else {
Ok(x / y)
}
}
// 使用match处理Result
match divide(10.0, 2.0) {
Ok(result) => println!("结果: {}", result),
Err(e) => println!("错误: {}", e),
}
```
### 3.2.4 ?操作符使用技巧
`?`操作符简化了错误处理:
```rust
use std::fs::File;
use std::io::{self, Read};
fn read_file_contents(path: &str) -> Result<String, io::Error> {
let mut file = File::open(path)?; // 如果发生错误,立即返回错误
let mut contents = String::new();
file.read_to_string(&mut contents)?; // 同上
Ok(contents)
}
```
## 3.3 泛型编程精要
### 3.3.1 泛型函数和结构体
泛型允许我们编写灵活可复用的代码:
```rust
// 泛型函数
fn largest<T: PartialOrd>(list: &[T]) -> &T {
let mut largest = &list[0];
for item in list.iter() {
if item > largest {
largest = item;
}
}
largest
}
// 泛型结构体
struct Point<T> {
x: T,
y: T,
}
impl<T> Point<T> {
fn new(x: T, y: T) -> Self {
Point { x, y }
}
}
```
### 3.3.2 泛型约束
通过trait约束限制泛型类型
```rust
use std::fmt::Display;
fn print_pair<T: Display>(x: T, y: T) {
println!("x = {}, y = {}", x, y);
}
// 多重约束
fn describe<T: Display + Clone>(value: T) {
let copy = value.clone();
println!("值是: {}", copy);
}
// where子句
fn complex_function<T, U>(t: T, u: U) -> i32
where
T: Display + Clone,
U: Clone + Default,
{
// 实现
42
}
```
### 3.3.3 关联类型
在trait中使用关联类型提高代码清晰度
```rust
trait Container {
type Item;
fn get(&self) -> Option<&Self::Item>;
fn insert(&mut self, item: Self::Item);
}
struct Stack<T> {
items: Vec<T>,
}
impl<T> Container for Stack<T> {
type Item = T;
fn get(&self) -> Option<&Self::Item> {
self.items.last()
}
fn insert(&mut self, item: Self::Item) {
self.items.push(item);
}
}
```
## 3.4 Trait系统深入
### 3.4.1 Trait定义和实现
trait定义了类型可以实现的行为
```rust
// 定义trait
trait Describable {
fn describe(&self) -> String;
// 带有默认实现的方法
fn default_description(&self) -> String {
String::from("这是一个可描述的对象")
}
}
// 为类型实现trait
struct Person {
name: String,
age: u32,
}
impl Describable for Person {
fn describe(&self) -> String {
format!("{}{}岁", self.name, self.age)
}
}
```
### 3.4.2 Trait对象
使用trait对象实现运行时多态
```rust
trait Animal {
fn make_sound(&self) -> String;
}
struct Dog {
name: String,
}
struct Cat {
name: String,
}
impl Animal for Dog {
fn make_sound(&self) -> String {
format!("{}: 汪汪!", self.name)
}
}
impl Animal for Cat {
fn make_sound(&self) -> String {
format!("{}: 喵喵!", self.name)
}
}
// 使用trait对象
fn animal_sounds(animals: Vec<Box<dyn Animal>>) {
for animal in animals {
println!("{}", animal.make_sound());
}
}
```
## 3.5 实战项目:文件处理工具库
在本章的最后,我们将实现一个文件处理工具库,整合所学的类型系统知识。完整代码请参考`examples/ex03`目录。
### 3.5.1 核心特性
1. 强类型的文件操作API
2. 完整的错误处理链
3. 可扩展的插件系统通过trait实现
4. 泛型化的数据处理接口
### 3.5.2 示例代码片段
```rust
// error.rs
#[derive(Debug)]
pub enum FileError {
NotFound(String),
PermissionDenied(String),
ReadError(String),
WriteError(String),
}
// traits.rs
pub trait FileProcessor {
type Error;
fn process(&self, content: &str) -> Result<String, Self::Error>;
}
// file_ops.rs
pub struct SafeFileReader {
path: String,
}
impl SafeFileReader {
pub fn new(path: String) -> Self {
SafeFileReader { path }
}
pub fn read_and_process<P: FileProcessor>(
&self,
processor: &P
) -> Result<String, FileError> {
let content = std::fs::read_to_string(&self.path)
.map_err(|e| FileError::ReadError(e.to_string()))?;
processor.process(&content)
.map_err(|_| FileError::ReadError("处理失败".to_string()))
}
}
```
### 3.5.3 使用示例
```rust
// main.rs
struct UpperCaseProcessor;
impl FileProcessor for UpperCaseProcessor {
type Error = String;
fn process(&self, content: &str) -> Result<String, Self::Error> {
Ok(content.to_uppercase())
}
}
fn main() -> Result<(), FileError> {
let reader = SafeFileReader::new("input.txt".to_string());
let processor = UpperCaseProcessor;
let processed_content = reader.read_and_process(&processor)?;
println!("处理后的内容:\n{}", processed_content);
Ok(())
}
```
## 本章小结
在本章中我们深入探讨了Rust的类型系统包括
1. 类型系统的基础概念和安全保证
2. Option和Result的实际应用
3. 泛型编程的核心概念
4. trait系统的深入使用
5. 实战项目中的综合应用
通过文件处理工具库的实现,我们看到了如何将这些概念组合使用,创建类型安全、错误处理完善的实用程序。
## 练习题
1. 实现一个泛型的Stack数据结构包含push、pop和peek方法
2. 为文件处理工具库添加新的处理器,如行号添加器、关键词统计器等
3. 使用trait对象实现插件系统允许在运行时动态加载不同的文件处理器
4. 扩展错误类型,添加更多具体的错误场景和错误信息
## 扩展阅读
- [Rust官方文档泛型](https://doc.rust-lang.org/book/ch10-00-generics.html)
- [Rust官方文档trait](https://doc.rust-lang.org/book/ch10-02-traits.html)
- [Rust错误处理最佳实践](https://rust-lang.github.io/rust-clippy/master/index.html#error)

10
examples/ex03/Cargo.toml Normal file
View File

@ -0,0 +1,10 @@
[package]
name = "file_processor"
version = "0.1.0"
edition = "2021"
authors = ["Rust实战精要"]
description = "第3章示例文件处理工具库"
[dependencies]
thiserror = "1.0" # 简化错误定义
anyhow = "1.0" # 错误处理工具

View File

@ -0,0 +1,64 @@
use std::fmt;
use std::io;
use thiserror::Error;
/// 文件处理错误类型
#[derive(Error, Debug)]
pub enum FileError {
/// 文件未找到错误
#[error("文件未找到: {0}")]
NotFound(String),
/// 权限错误
#[error("权限不足: {0}")]
PermissionDenied(String),
/// 读取错误
#[error("读取文件失败: {0}")]
ReadError(String),
/// 写入错误
#[error("写入文件失败: {0}")]
WriteError(String),
/// 处理错误
#[error("处理内容失败: {0}")]
ProcessError(String),
/// IO错误
#[error("IO错误: {0}")]
IoError(#[from] io::Error),
/// 未知错误
#[error("未知错误: {0}")]
Unknown(String),
}
// 实现Display trait提供更友好的错误信息
impl fmt::Display for FileError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
FileError::NotFound(path) => write!(f, "找不到文件: {}", path),
FileError::PermissionDenied(path) => write!(f, "没有权限访问文件: {}", path),
FileError::ReadError(msg) => write!(f, "读取文件时出错: {}", msg),
FileError::WriteError(msg) => write!(f, "写入文件时出错: {}", msg),
FileError::ProcessError(msg) => write!(f, "处理文件内容时出错: {}", msg),
FileError::IoError(err) => write!(f, "IO错误: {}", err),
FileError::Unknown(msg) => write!(f, "未知错误: {}", msg),
}
}
}
// 从字符串创建错误的便捷方法
impl From<&str> for FileError {
fn from(error: &str) -> Self {
FileError::Unknown(error.to_string())
}
}
// 从字符串创建错误的便捷方法
impl From<String> for FileError {
fn from(error: String) -> Self {
FileError::Unknown(error)
}
}

View File

@ -0,0 +1,197 @@
use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::path::Path;
use crate::error::FileError;
use crate::traits::{ContentAnalyzer, ContentTransformer, FileProcessor, LineFilter};
/// 安全的文件读取器
pub struct SafeFileReader {
path: String,
}
impl SafeFileReader {
/// 创建新的文件读取器
///
/// # 参数
/// * `path` - 文件路径
pub fn new(path: String) -> Self {
SafeFileReader { path }
}
/// 读取文件内容
///
/// # 返回
/// * `Result<String, FileError>` - 文件内容或错误
pub fn read(&self) -> Result<String, FileError> {
let path = Path::new(&self.path);
if !path.exists() {
return Err(FileError::NotFound(self.path.clone()));
}
fs::read_to_string(path)
.map_err(|e| match e.kind() {
io::ErrorKind::PermissionDenied => FileError::PermissionDenied(self.path.clone()),
_ => FileError::ReadError(e.to_string()),
})
}
/// 读取并处理文件内容
///
/// # 参数
/// * `processor` - 实现了FileProcessor trait的处理器
///
/// # 返回
/// * `Result<String, FileError>` - 处理后的内容或错误
pub fn read_and_process<P>(&self, processor: &P) -> Result<String, FileError>
where
P: FileProcessor,
{
let content = self.read()?;
processor.process(&content)
.map_err(|e| FileError::ProcessError(format!("{:?}", e)))
}
/// 读取并分析文件内容
///
/// # 参数
/// * `analyzer` - 实现了ContentAnalyzer trait的分析器
///
/// # 返回
/// * `Result<T, FileError>` - 分析结果或错误
pub fn read_and_analyze<A, T>(&self, analyzer: &A) -> Result<T, FileError>
where
A: ContentAnalyzer<T>,
{
let content = self.read()?;
analyzer.analyze(&content)
.map_err(|e| FileError::ProcessError(format!("{:?}", e)))
}
/// 读取并过滤文件内容
///
/// # 参数
/// * `filter` - 实现了LineFilter trait的过滤器
///
/// # 返回
/// * `Result<String, FileError>` - 过滤后的内容或错误
pub fn read_and_filter<F>(&self, filter: &F) -> Result<String, FileError>
where
F: LineFilter,
{
let content = self.read()?;
let filtered = content
.lines()
.filter(|line| filter.should_keep(line))
.collect::<Vec<&str>>()
.join("\n");
Ok(filtered)
}
}
/// 安全的文件写入器
pub struct SafeFileWriter {
path: String,
}
impl SafeFileWriter {
/// 创建新的文件写入器
///
/// # 参数
/// * `path` - 文件路径
pub fn new(path: String) -> Self {
SafeFileWriter { path }
}
/// 写入内容到文件
///
/// # 参数
/// * `content` - 要写入的内容
///
/// # 返回
/// * `Result<(), FileError>` - 成功或错误
pub fn write(&self, content: &str) -> Result<(), FileError> {
let mut file = File::create(&self.path)
.map_err(|e| match e.kind() {
io::ErrorKind::PermissionDenied => FileError::PermissionDenied(self.path.clone()),
_ => FileError::WriteError(e.to_string()),
})?;
file.write_all(content.as_bytes())
.map_err(|e| FileError::WriteError(e.to_string()))?;
Ok(())
}
/// 转换并写入内容到文件
///
/// # 参数
/// * `content` - 原始内容
/// * `transformer` - 实现了ContentTransformer trait的转换器
///
/// # 返回
/// * `Result<(), FileError>` - 成功或错误
pub fn transform_and_write<T>(&self, content: &str, transformer: &T) -> Result<(), FileError>
where
T: ContentTransformer,
{
let transformed = transformer.transform(content)
.map_err(|e| FileError::ProcessError(format!("{:?}", e)))?;
self.write(&transformed)
}
}
/// 文件处理管道
///
/// 允许链式调用多个处理器
pub struct ProcessingPipeline<'a> {
processors: Vec<&'a dyn FileProcessor<Error = String>>,
}
impl<'a> ProcessingPipeline<'a> {
/// 创建新的处理管道
pub fn new() -> Self {
ProcessingPipeline {
processors: Vec::new(),
}
}
/// 添加处理器到管道
///
/// # 参数
/// * `processor` - 实现了FileProcessor trait的处理器
pub fn add_processor(&mut self, processor: &'a dyn FileProcessor<Error = String>) -> &mut Self {
self.processors.push(processor);
self
}
/// 执行处理管道
///
/// # 参数
/// * `content` - 要处理的内容
///
/// # 返回
/// * `Result<String, FileError>` - 处理后的内容或错误
pub fn process(&self, content: &str) -> Result<String, FileError> {
let mut result = content.to_string();
for processor in &self.processors {
result = processor.process(&result)
.map_err(|e| FileError::ProcessError(e))?;
}
Ok(result)
}
}
impl<'a> Default for ProcessingPipeline<'a> {
fn default() -> Self {
Self::new()
}
}

215
examples/ex03/src/main.rs Normal file
View File

@ -0,0 +1,215 @@
mod error;
mod file_ops;
mod traits;
mod utils;
use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
use error::FileError;
use file_ops::{ProcessingPipeline, SafeFileReader, SafeFileWriter};
use traits::{ContentAnalyzer, FileProcessor};
use utils::{
EmptyLineFilter, KeywordFilter, LineNumberProcessor, LowerCaseProcessor,
MarkdownToHtmlTransformer, TextStatistics, TextStatisticsAnalyzer, UpperCaseProcessor,
WordFrequencyAnalyzer,
};
/// 创建示例文件
fn create_sample_file(path: &str, content: &str) -> Result<(), FileError> {
let mut file = File::create(path).map_err(FileError::IoError)?;
file.write_all(content.as_bytes()).map_err(FileError::IoError)?;
Ok(())
}
/// 展示文件处理器的使用
fn demo_file_processors() -> Result<(), FileError> {
println!("\n=== 文件处理器演示 ===");
// 创建示例文件
let sample_path = "sample.txt";
let sample_content = "这是第一行文本。\n这是第二行文本。\n\n这是第四行文本。";
create_sample_file(sample_path, sample_content)?;
println!("创建了示例文件: {}", sample_path);
// 创建文件读取器
let reader = SafeFileReader::new(sample_path.to_string());
// 使用大写处理器
let upper_processor = UpperCaseProcessor;
let upper_result = reader.read_and_process(&upper_processor)?;
println!("\n使用{}:\n{}", upper_processor.name(), upper_result);
// 使用小写处理器
let lower_processor = LowerCaseProcessor;
let lower_result = reader.read_and_process(&lower_processor)?;
println!("\n使用{}:\n{}", lower_processor.name(), lower_result);
// 使用行号处理器
let line_num_processor = LineNumberProcessor;
let line_num_result = reader.read_and_process(&line_num_processor)?;
println!("\n使用{}:\n{}", line_num_processor.name(), line_num_result);
// 使用空行过滤器
let empty_line_filter = EmptyLineFilter;
let filtered_content = reader.read_and_filter(&empty_line_filter)?;
println!("\n使用空行过滤器:\n{}", filtered_content);
// 使用关键词过滤器
let keyword_filter = KeywordFilter::new("第二".to_string(), true);
let keyword_filtered = reader.read_and_filter(&keyword_filter)?;
println!("\n使用关键词过滤器 (关键词: '第二'):\n{}", keyword_filtered);
Ok(())
}
/// 展示处理管道的使用
fn demo_processing_pipeline() -> Result<(), FileError> {
println!("\n=== 处理管道演示 ===");
// 创建示例文件
let sample_path = "pipeline_sample.txt";
let sample_content = "第一行\n第二行\n第三行\n第四行";
create_sample_file(sample_path, sample_content)?;
println!("创建了示例文件: {}", sample_path);
// 创建文件读取器
let reader = SafeFileReader::new(sample_path.to_string());
let content = reader.read()?;
// 创建处理管道
let mut pipeline = ProcessingPipeline::new();
// 添加处理器
pipeline
.add_processor(&LineNumberProcessor)
.add_processor(&UpperCaseProcessor);
// 执行管道
let result = pipeline.process(&content)?;
println!("\n处理管道结果 (行号 -> 大写):\n{}", result);
Ok(())
}
/// 展示内容分析器的使用
fn demo_content_analyzers() -> Result<(), FileError> {
println!("\n=== 内容分析器演示 ===");
// 创建示例文件
let sample_path = "analyzer_sample.txt";
let sample_content = "这是一个示例文本文件。\n它包含多行文本。\n\n这些文本将被分析。\n我们可以统计单词频率和其他指标。";
create_sample_file(sample_path, sample_content)?;
println!("创建了示例文件: {}", sample_path);
// 创建文件读取器
let reader = SafeFileReader::new(sample_path.to_string());
// 使用文本统计分析器
let stats_analyzer = TextStatisticsAnalyzer;
let stats: TextStatistics = reader.read_and_analyze(&stats_analyzer)?;
println!("\n文本统计结果:");
println!("总行数: {}", stats.line_count);
println!("总字数: {}", stats.word_count);
println!("总字符数: {}", stats.char_count);
println!("非空行数: {}", stats.non_empty_lines);
// 使用单词频率分析器
let word_analyzer = WordFrequencyAnalyzer;
let word_counts: HashMap<String, usize> = reader.read_and_analyze(&word_analyzer)?;
println!("\n单词频率统计 (前5个):");
let mut words: Vec<(&String, &usize)> = word_counts.iter().collect();
words.sort_by(|a, b| b.1.cmp(a.1));
for (i, (word, count)) in words.iter().take(5).enumerate() {
println!("{}. {} - 出现{}", i + 1, word, count);
}
Ok(())
}
/// 展示内容转换器的使用
fn demo_content_transformer() -> Result<(), FileError> {
println!("\n=== 内容转换器演示 ===");
// 创建示例Markdown文件
let md_path = "sample.md";
let md_content = "# 示例标题\n\n## 小标题\n\n这是一段普通文本。\n\n### 小小标题\n\n这是另一段文本。";
create_sample_file(md_path, md_content)?;
println!("创建了示例Markdown文件: {}", md_path);
// 创建文件读取器和写入器
let reader = SafeFileReader::new(md_path.to_string());
let writer = SafeFileWriter::new("sample.html".to_string());
// 读取Markdown内容
let content = reader.read()?;
// 使用Markdown到HTML转换器
let transformer = MarkdownToHtmlTransformer;
writer.transform_and_write(&content, &transformer)?;
println!("\nMarkdown已转换为HTML并保存到 sample.html");
Ok(())
}
/// 自定义处理器示例
struct ReverseLineProcessor;
impl FileProcessor for ReverseLineProcessor {
type Error = String;
fn process(&self, content: &str) -> Result<String, Self::Error> {
let reversed = content
.lines()
.map(|line| line.chars().rev().collect::<String>())
.collect::<Vec<String>>()
.join("\n");
Ok(reversed)
}
fn name(&self) -> String {
String::from("行反转处理器")
}
fn description(&self) -> String {
String::from("将每行文本反转")
}
}
fn main() -> Result<(), FileError> {
println!("=== 文件处理工具库演示 ===");
// 演示文件处理器
demo_file_processors()?;
// 演示处理管道
demo_processing_pipeline()?;
// 演示内容分析器
demo_content_analyzers()?;
// 演示内容转换器
demo_content_transformer()?;
// 使用自定义处理器
println!("\n=== 自定义处理器演示 ===");
let sample_path = "custom_sample.txt";
let sample_content = "这是第一行\n这是第二行\n这是第三行";
create_sample_file(sample_path, sample_content)?;
let reader = SafeFileReader::new(sample_path.to_string());
let reverse_processor = ReverseLineProcessor;
let result = reader.read_and_process(&reverse_processor)?;
println!("\n使用{}:\n{}", reverse_processor.name(), result);
println!("\n所有演示完成!");
Ok(())
}

View File

@ -0,0 +1,76 @@
use std::fmt::Debug;
/// 文件处理器trait
///
/// 定义了处理文件内容的通用接口
pub trait FileProcessor {
/// 处理器可能产生的错误类型
type Error: Debug;
/// 处理文件内容的方法
///
/// # 参数
/// * `content` - 要处理的文件内容
///
/// # 返回
/// * `Result<String, Self::Error>` - 处理后的内容或错误
fn process(&self, content: &str) -> Result<String, Self::Error>;
/// 处理器名称(默认实现)
fn name(&self) -> String {
String::from("默认处理器")
}
/// 处理器描述(默认实现)
fn description(&self) -> String {
String::from("处理文件内容")
}
}
/// 文件过滤器trait
///
/// 用于过滤文件内容的行
pub trait LineFilter {
/// 判断一行是否应该被保留
///
/// # 参数
/// * `line` - 要判断的行
///
/// # 返回
/// * `bool` - true表示保留false表示过滤掉
fn should_keep(&self, line: &str) -> bool;
}
/// 文件转换器trait
///
/// 用于转换文件内容
pub trait ContentTransformer {
/// 转换器可能产生的错误类型
type Error: Debug;
/// 转换文件内容
///
/// # 参数
/// * `content` - 要转换的内容
///
/// # 返回
/// * `Result<String, Self::Error>` - 转换后的内容或错误
fn transform(&self, content: &str) -> Result<String, Self::Error>;
}
/// 文件分析器trait
///
/// 用于分析文件内容并生成统计信息
pub trait ContentAnalyzer<T> {
/// 分析器可能产生的错误类型
type Error: Debug;
/// 分析文件内容
///
/// # 参数
/// * `content` - 要分析的内容
///
/// # 返回
/// * `Result<T, Self::Error>` - 分析结果或错误
fn analyze(&self, content: &str) -> Result<T, Self::Error>;
}

240
examples/ex03/src/utils.rs Normal file
View File

@ -0,0 +1,240 @@
use std::collections::HashMap;
use std::path::Path;
use crate::traits::{ContentAnalyzer, ContentTransformer, FileProcessor, LineFilter};
/// 大写转换处理器
pub struct UpperCaseProcessor;
impl FileProcessor for UpperCaseProcessor {
type Error = String;
fn process(&self, content: &str) -> Result<String, Self::Error> {
Ok(content.to_uppercase())
}
fn name(&self) -> String {
String::from("大写转换处理器")
}
fn description(&self) -> String {
String::from("将文本内容转换为大写")
}
}
/// 小写转换处理器
pub struct LowerCaseProcessor;
impl FileProcessor for LowerCaseProcessor {
type Error = String;
fn process(&self, content: &str) -> Result<String, Self::Error> {
Ok(content.to_lowercase())
}
fn name(&self) -> String {
String::from("小写转换处理器")
}
fn description(&self) -> String {
String::from("将文本内容转换为小写")
}
}
/// 行号添加处理器
pub struct LineNumberProcessor;
impl FileProcessor for LineNumberProcessor {
type Error = String;
fn process(&self, content: &str) -> Result<String, Self::Error> {
let numbered = content
.lines()
.enumerate()
.map(|(i, line)| format!("{}: {}", i + 1, line))
.collect::<Vec<String>>()
.join("\n");
Ok(numbered)
}
fn name(&self) -> String {
String::from("行号添加处理器")
}
fn description(&self) -> String {
String::from("为每行添加行号")
}
}
/// 空行过滤器
pub struct EmptyLineFilter;
impl LineFilter for EmptyLineFilter {
fn should_keep(&self, line: &str) -> bool {
!line.trim().is_empty()
}
}
/// 关键词过滤器
pub struct KeywordFilter {
keyword: String,
case_sensitive: bool,
}
impl KeywordFilter {
/// 创建新的关键词过滤器
///
/// # 参数
/// * `keyword` - 要过滤的关键词
/// * `case_sensitive` - 是否区分大小写
pub fn new(keyword: String, case_sensitive: bool) -> Self {
KeywordFilter {
keyword,
case_sensitive,
}
}
}
impl LineFilter for KeywordFilter {
fn should_keep(&self, line: &str) -> bool {
if self.case_sensitive {
line.contains(&self.keyword)
} else {
line.to_lowercase().contains(&self.keyword.to_lowercase())
}
}
}
/// Markdown转HTML转换器
pub struct MarkdownToHtmlTransformer;
impl ContentTransformer for MarkdownToHtmlTransformer {
type Error = String;
fn transform(&self, content: &str) -> Result<String, Self::Error> {
// 这里只是一个简单的实现真实场景可能需要使用专门的Markdown解析库
let mut html = String::from("<html><body>\n");
for line in content.lines() {
if line.starts_with("# ") {
html.push_str(&format!("<h1>{}</h1>\n", &line[2..]));
} else if line.starts_with("## ") {
html.push_str(&format!("<h2>{}</h2>\n", &line[3..]));
} else if line.starts_with("### ") {
html.push_str(&format!("<h3>{}</h3>\n", &line[4..]));
} else if line.trim().is_empty() {
html.push_str("<br>\n");
} else {
html.push_str(&format!("<p>{}</p>\n", line));
}
}
html.push_str("</body></html>");
Ok(html)
}
}
/// 文本统计分析器
pub struct TextStatisticsAnalyzer;
/// 文本统计结果
#[derive(Debug)]
pub struct TextStatistics {
/// 总行数
pub line_count: usize,
/// 总字数
pub word_count: usize,
/// 总字符数
pub char_count: usize,
/// 非空行数
pub non_empty_lines: usize,
}
impl ContentAnalyzer<TextStatistics> for TextStatisticsAnalyzer {
type Error = String;
fn analyze(&self, content: &str) -> Result<TextStatistics, Self::Error> {
let lines: Vec<&str> = content.lines().collect();
let line_count = lines.len();
let char_count = content.chars().count();
let word_count = content
.split_whitespace()
.count();
let non_empty_lines = lines
.iter()
.filter(|line| !line.trim().is_empty())
.count();
Ok(TextStatistics {
line_count,
word_count,
char_count,
non_empty_lines,
})
}
}
/// 单词频率分析器
pub struct WordFrequencyAnalyzer;
impl ContentAnalyzer<HashMap<String, usize>> for WordFrequencyAnalyzer {
type Error = String;
fn analyze(&self, content: &str) -> Result<HashMap<String, usize>, Self::Error> {
let mut word_counts = HashMap::new();
for word in content.split_whitespace() {
// 移除标点符号并转为小写
let clean_word = word
.chars()
.filter(|c| c.is_alphanumeric())
.collect::<String>()
.to_lowercase();
if !clean_word.is_empty() {
*word_counts.entry(clean_word).or_insert(0) += 1;
}
}
Ok(word_counts)
}
}
/// 文件扩展名检查器
pub struct FileExtensionChecker {
allowed_extensions: Vec<String>,
}
impl FileExtensionChecker {
/// 创建新的文件扩展名检查器
///
/// # 参数
/// * `extensions` - 允许的扩展名列表
pub fn new(extensions: Vec<String>) -> Self {
FileExtensionChecker {
allowed_extensions: extensions,
}
}
/// 检查文件扩展名是否允许
///
/// # 参数
/// * `file_path` - 文件路径
///
/// # 返回
/// * `bool` - 是否允许
pub fn is_allowed(&self, file_path: &str) -> bool {
let path = Path::new(file_path);
if let Some(extension) = path.extension() {
if let Some(ext_str) = extension.to_str() {
return self.allowed_extensions.iter().any(|allowed| allowed == ext_str);
}
}
false
}
}

View File

@ -12,7 +12,7 @@
- 实例:实现安全字符串处理器(避免悬垂指针)
**第3章 类型系统实战**
- 提示词:`模式匹配解构Option | Result错误传播?操作符 | 泛型结构体实现 | trait约束实战`
- 提示词:`模式匹配解构Option | Result错误传播?操作符 | 泛型结构体实现 | trait约束实战|unwrap()相关`
- 项目:文件读取工具(强错误处理链)
**第4章 结构化工程:模块与包**