返回

用Rust打造一个迷你todo命令行工具:从零到一的新手入门指南

前端

本文介绍如何使用Rust语言从零开始开发一个简易的Todo列表命令行应用,旨在帮助开发者理解Rust的基本用法及操作技巧。通过创建、读取、更新和删除(CRUD)todo项,用户可以管理自己的日常任务。

Rust环境设置

在开始编程之前,需要确保已安装Rust编程语言环境。可以通过以下命令检查是否已经安装了Rust:

rustc --version

如果未安装,请访问Rust官网下载并按照官方指南进行安装。

创建项目

使用Cargo(Rust的包管理器和构建工具)创建一个新项目。在命令行中运行以下指令:

cargo new todo-cli --bin
cd todo-cli

这会生成一个新的名为todo-cli的二进制项目结构,包含必要的文件如src/main.rs

文件读写操作

为了存储Todo列表项,我们需要实现对文件的操作。这里将使用Rust标准库中的std::fs模块进行文件读取和写入。

写入文件

当用户添加新的todo项时,需要将其保存到磁盘上的文件中:

use std::fs;
use std::io::{self, Write};

fn save_todo(todo: &str) -> io::Result<()> {
    let mut file = fs::OpenOptions::new()
        .write(true)
        .append(true)
        .create(true)
        .open("todo.txt")?;
    
    writeln!(file, "{}", todo)?;
    
    Ok(())
}

读取文件

当用户请求查看所有已保存的待办事项时,可以从todo.txt中读取并打印出内容:

use std::fs;

fn load_todos() -> Result<String, Box<dyn std::error::Error>> {
    let contents = fs::read_to_string("todo.txt")?;
    
    Ok(contents)
}

命令行交互

为了让用户能够与程序互动,使用了std::io::stdin()来获取用户的输入:

use std::io;

fn get_input(prompt: &str) -> String {
    println!("{}", prompt);
    let mut input = String::new();
    
    io::stdin().read_line(&mut input).unwrap();
    
    input.trim_end_matches('\n').to_string()
}

实现CRUD操作

结合上述函数,我们可以构建一个简单的命令行工具来管理todo项。

添加和显示待办事项

通过save_todo()load_todos()实现了添加新待办任务及查看所有任务的功能:

fn main() {
    let action = get_input("Enter action (add|list):");
    
    if action == "add" {
        let todo = get_input("Enter your new todo:");
        save_todo(&todo).expect("Failed to save todo");
        println!("Todo saved!");
    } else if action == "list" {
        match load_todos() {
            Ok(todos) => println!("{}", todos),
            Err(e) => eprintln!("Error loading todos: {}", e),
        }
    }
}

更新和删除待办事项

实现更新或删除功能相对复杂,需要先读取文件内容到内存中,对特定项进行修改后再写回文件。这里仅展示一个简单的删除逻辑:

fn delete_todo(todo_to_remove: &str) -> Result<(), Box<dyn std::error::Error>> {
    let todos = load_todos()?;
    
    // 暂时不处理多条相同内容的待办事项,只保留第一个匹配项。
    if let Some(position) = todos.lines().position(|line| line == todo_to_remove) {
        fs::write("todo.txt", &todos.split_whitespace().enumerate()
            .filter_map(|(index, item)| if index != position {Some(item)} else {None})
            .collect::<Vec<_>>().join("\n"))?;
    }
    
    Ok(())
}

安全与异常处理

在上述代码中,我们使用了expect()?操作符来简化错误处理。实际应用中应考虑更详细的错误检查机制以及用户输入的验证。

输入验证示例

为确保待办事项内容的有效性,可以添加基本的输入长度限制:

fn get_input(prompt: &str) -> String {
    println!("{}", prompt);
    
    let mut input = String::new();
    io::stdin().read_line(&mut input).unwrap();
    
    if input.trim_end_matches('\n').len() < 5 {
        panic!("Todo must be at least 5 characters long.");
    }
    
    input.trim_end_matches('\n').to_string()
}

通过本教程,开发者可以了解如何使用Rust语言构建简单的命令行应用。这不仅涵盖了基本的文件操作,还包括了与用户交互的关键组件。

进一步学习资源