Rust 综合练习:构建 TODO 列表应用

举报
数字扫地僧 发表于 2025/06/10 19:13:35 2025/06/10
【摘要】 在编程的世界里,Rust 语言正以其独特的魅力吸引着越来越多的开发者。它不仅注重性能,还提供了强大的内存安全保障,无需借助垃圾回收机制。今天,我将带领大家一起动手构建一个简单的 TODO 列表应用,通过这个综合练习,深入体会 Rust 的开发之道。 I. 开发环境搭建 (一)Rust 安装在开始之前,我们需要将 Rust 安装到本地机器上。对于 Windows 用户,可以从官方资源下载自安装...

在编程的世界里,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)
}

这里,我们借助 serdeserde_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 总结

TODO 列表应用开发
开发环境搭建
Rust 安装
编辑器配置
项目初始化与结构规划
项目创建
项目结构规划
核心功能开发
任务管理功能
定义任务结构体
实现任务操作函数
数据持久化功能
用户界面功能
项目整合与运行

VI. 项目扩展与优化

(一)功能扩展

  1. 任务优先级 :可以为任务添加优先级字段,比如高、中、低三个级别。在显示任务列表时,按照优先级排序,让用户更直观地看到重要任务。
  2. 任务分类 :引入分类功能,用户可以将任务分成不同的类别,如工作、生活、学习等。这样便于用户对任务进行管理和筛选。
  3. 任务提醒 :集成定时提醒功能,当任务的截止日期临近时,应用可以发送提醒通知。

(二)性能优化

  1. 数据存储优化 :对于任务数据量较大的情况,可以考虑使用更高效的存储格式或数据库来替代本地文件存储,提高数据读写性能。
  2. 界面交互优化 :在用户界面层面,可以减少不必要的输入输出操作,优化菜单展示和任务列表渲染,提升用户体验。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。