Rust 综合练习:构建 TODO 列表应用
在编程的世界里,Rust 语言正以其独特的魅力吸引着越来越多的开发者。它不仅注重性能,还提供了强大的内存安全保障,无需借助垃圾回收机制。今天,我将带领大家一起动手构建一个简单的 TODO 列表应用,通过这个综合练习,深入体会 Rust 的开发之道。
I. 开发环境搭建
(一)Rust 安装
在开始之前,我们需要将 Rust 安装到本地机器上。对于 Windows 用户,可以从官方资源下载自安装程序,运行后遵循安装向导即可完成安装。macOS 用户则可借助 Homebrew 这个包管理工具,通过在终端输入 brew install rust
命令来安装。至于 Linux 用户,基于 Debian 的系统使用 apt-get install rustc
命令,而基于 RedHat 的系统使用 yum install rust
命令。
安装完成后,在命令行输入 rustc --version
,看到类似 rustc 1.70.0
的输出,就说明 Rust 编译器已成功安装。
(二)编辑器配置
我推荐使用 Visual Studio Code(VS Code)作为 Rust 开发的编辑器。安装好 VS Code 后,需要安装 Rust Analyzer 插件。它为编辑器提供了智能代码补全、语法高亮以及代码格式化等功能。安装完成后,VS Code 就能很好地支持 Rust 语言开发了。
II. 项目初始化与结构规划
(一)项目创建
打开终端,输入 cargo new todo_app
命令,Cargo 就会帮我们创建一个名为 todo_app 的新项目。进入项目文件夹,可以看到 Cargo 自动生成了项目的基本结构,其中 Cargo.toml
文件是项目的配置文件,而 src/main.rs
是项目的主文件。
(二)项目结构规划
考虑到 TODO 应用的功能需求,我们初步规划项目结构如下:
src/main.rs
:作为项目的入口文件,主要负责应用的启动和整体流程控制。src/task.rs
:用于定义任务相关的数据结构和操作函数,例如任务的添加、修改、标记完成等。src/storage.rs
:负责任务数据的持久化存储和加载,可以考虑使用本地文件系统来存储任务数据。src/ui.rs
:处理用户界面相关的逻辑,接收用户输入并展示任务列表等信息。
III. 核心功能开发
(一)任务管理功能
1. 定义任务结构体
在 src/task.rs
文件中,我们定义一个任务结构体:
pub struct Task {
pub id: u32,
pub title: String,
pub completed: bool,
}
这里,id
是任务的唯一标识,title
存储任务的标题,completed
表示任务是否已完成。
2. 实现任务操作函数
接着,我们实现一些对任务的基本操作函数,比如添加任务、标记任务完成等:
use std::collections::HashMap;
pub struct TaskManager {
tasks: HashMap<u32, Task>,
next_id: u32,
}
impl TaskManager {
pub fn new() -> Self {
TaskManager {
tasks: HashMap::new(),
next_id: 1,
}
}
pub fn add_task(&mut self, title: String) -> u32 {
let id = self.next_id;
let task = Task {
id,
title,
completed: false,
};
self.tasks.insert(id, task);
self.next_id += 1;
id
}
pub fn toggle_task_status(&mut self, id: u32) -> Option<()> {
if let Some(task) = self.tasks.get_mut(&id) {
task.completed = !task.completed;
Some(())
} else {
None
}
}
pub fn delete_task(&mut self, id: u32) -> Option<Task> {
self.tasks.remove(&id)
}
pub fn get_all_tasks(&self) -> Vec<&Task> {
let mut tasks: Vec<&Task> = self.tasks.values().collect();
tasks.sort_by(|a, b| a.id.cmp(&b.id));
tasks
}
}
TaskManager
结构体负责管理所有任务。通过 add_task
函数可以添加新任务,toggle_task_status
函数用于切换任务的完成状态,delete_task
函数删除指定任务,get_all_tasks
函数获取所有任务列表。
(二)数据持久化功能
在 src/storage.rs
文件中,我们实现任务数据的存储和加载功能:
use crate::task::{Task, TaskManager};
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::Path;
#[derive(Serialize, Deserialize)]
struct StorageData {
tasks: Vec<Task>,
next_id: u32,
}
pub fn save_tasks(task_manager: &TaskManager, file_path: &str) -> std::io::Result<()> {
let storage_data = StorageData {
tasks: task_manager.get_all_tasks().iter().map(|task| (**task).clone()).collect(),
next_id: task_manager.next_id,
};
let serialized = serde_json::to_string(&storage_data)?;
fs::write(file_path, serialized)
}
pub fn load_tasks(file_path: &str) -> std::io::Result<TaskManager> {
if !Path::new(file_path).exists() {
return Ok(TaskManager::new());
}
let serialized = fs::read_to_string(file_path)?;
let storage_data: StorageData = serde_json::from_str(&serialized)?;
let mut task_manager = TaskManager {
tasks: HashMap::new(),
next_id: storage_data.next_id,
};
for task in storage_data.tasks {
task_manager.tasks.insert(task.id, task);
}
Ok(task_manager)
}
这里,我们借助 serde
和 serde_json
库来实现数据的序列化和反序列化。save_tasks
函数将任务管理器中的数据保存到指定文件,load_tasks
函数从文件加载任务数据并还原任务管理器状态。
(三)用户界面功能
在 src/ui.rs
文件中,我们处理用户交互逻辑:
use crate::task::{TaskManager, Task};
use std::io::{self, Write};
pub fn display_menu() {
println!("\n===== TODO 列表应用 =====");
println!("1. 添加任务");
println!("2. 列出所有任务");
println!("3. 标记任务完成/未完成");
println!("4. 删除任务");
println!("5. 退出");
print!("请选择操作 (1-5): ");
io::stdout().flush().unwrap();
}
pub fn add_task(task_manager: &mut TaskManager) {
print!("\n请输入任务标题: ");
io::stdout().flush().unwrap();
let mut title = String::new();
io::stdin().read_line(&mut title).unwrap();
let title = title.trim().to_string();
let id = task_manager.add_task(title);
println!("任务已添加,ID: {}", id);
}
pub fn list_tasks(task_manager: &TaskManager) {
println!("\n===== 任务列表 =====");
for task in task_manager.get_all_tasks() {
let status = if task.completed { "[x]" } else { "[ ]" };
println!("{}: {} - {}", status, task.id, task.title);
}
}
pub fn toggle_task_status(task_manager: &mut TaskManager) {
list_tasks(task_manager);
print!("\n请输入要切换状态的任务 ID: ");
io::stdout().flush().unwrap();
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
let id: u32 = match input.trim().parse() {
Ok(num) => num,
Err(_) => {
println!("无效的任务 ID");
return;
}
};
if task_manager.toggle_task_status(id).is_some() {
println!("任务状态已切换");
} else {
println!("未找到任务 ID: {}", id);
}
}
pub fn delete_task(task_manager: &mut TaskManager) {
list_tasks(task_manager);
print!("\n请输入要删除的任务 ID: ");
io::stdout().flush().unwrap();
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
let id: u32 = match input.trim().parse() {
Ok(num) => num,
Err(_) => {
println!("无效的任务 ID");
return;
}
};
if task_manager.delete_task(id).is_some() {
println!("任务已删除");
} else {
println!("未找到任务 ID: {}", id);
}
}
display_menu
函数展示应用的操作菜单,add_task
函数处理添加任务的逻辑,list_tasks
函数显示所有任务,toggle_task_status
函数切换任务完成状态,delete_task
函数删除任务。
IV. 项目整合与运行
在 src/main.rs
文件中,我们将各个模块整合在一起:
mod task;
mod storage;
mod ui;
use std::io::{self, Write};
use task::TaskManager;
use storage::load_tasks;
use storage::save_tasks;
fn main() {
let file_path = "todo_data.json";
let mut task_manager = match load_tasks(file_path) {
Ok(manager) => manager,
Err(_) => TaskManager::new(),
};
loop {
ui::display_menu();
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
let choice: u32 = match input.trim().parse() {
Ok(num) => num,
Err(_) => {
println!("无效的选择,请输入 1-5 之间的数字");
continue;
}
};
match choice {
1 => ui::add_task(&mut task_manager),
2 => ui::list_tasks(&task_manager),
3 => ui::toggle_task_status(&mut task_manager),
4 => ui::delete_task(&mut task_manager),
5 => {
match save_tasks(&task_manager, file_path) {
Ok(_) => println!("任务数据已保存,退出应用"),
Err(e) => eprintln!("保存任务数据时出错: {}", e),
}
break;
}
_ => println!("无效的选择,请输入 1-5 之间的数字"),
}
}
}
我们首先尝试从本地文件加载任务数据,如果文件不存在则初始化一个新的任务管理器。然后进入一个循环,根据用户的选择调用相应的用户界面函数来执行操作。当用户选择退出时,将任务数据保存到文件并退出应用。
V. mermaid 总结
VI. 项目扩展与优化
(一)功能扩展
- 任务优先级 :可以为任务添加优先级字段,比如高、中、低三个级别。在显示任务列表时,按照优先级排序,让用户更直观地看到重要任务。
- 任务分类 :引入分类功能,用户可以将任务分成不同的类别,如工作、生活、学习等。这样便于用户对任务进行管理和筛选。
- 任务提醒 :集成定时提醒功能,当任务的截止日期临近时,应用可以发送提醒通知。
(二)性能优化
- 数据存储优化 :对于任务数据量较大的情况,可以考虑使用更高效的存储格式或数据库来替代本地文件存储,提高数据读写性能。
- 界面交互优化 :在用户界面层面,可以减少不必要的输入输出操作,优化菜单展示和任务列表渲染,提升用户体验。
- 点赞
- 收藏
- 关注作者
评论(0)