Go语言实战案例- 开发一个ToDo命令行工具

在日常工作或学习中,记录待办事项(ToDo)是高效管理时间的重要方式。除了使用各种 GUI 工具,我们还可以用 Go 开发一个轻量级的 命令行 ToDo 工具,方便 geek 风格的用户在终端中快速记录和查看任务。

本文将一步步实现一个简单的命令行 ToDo 工具,支持以下功能:

  • 添加任务
  • 查看任务列表
  • 完成任务(删除或标记完成)
  • 数据本地存储(JSON 文件)

一、项目结构

项目结构如下:

bash 复制代码
todo-cli/
├── main.go       # 入口文件
├── todo.go       # 任务数据模型与存储逻辑
└── todos.json    # 本地存储文件

二、定义任务模型

我们需要一个 Task 结构体来表示待办事项,每个任务包含:

  • ID:任务编号
  • Title:任务标题
  • Done:是否完成

todo.go

go 复制代码
package main

import (
	"encoding/json"
	"os"
)

type Task struct {
	ID    int    `json:"id"`
	Title string `json:"title"`
	Done  bool   `json:"done"`
}

type ToDoList struct {
	Tasks []Task `json:"tasks"`
}

// 加载任务
func (t *ToDoList) Load(filename string) error {
	file, err := os.ReadFile(filename)
	if err != nil {
		// 文件不存在时初始化空任务列表
		t.Tasks = []Task{}
		return nil
	}
	return json.Unmarshal(file, t)
}

// 保存任务
func (t *ToDoList) Save(filename string) error {
	data, err := json.MarshalIndent(t, "", "  ")
	if err != nil {
		return err
	}
	return os.WriteFile(filename, data, 0644)
}

三、命令行参数解析

我们用 flag 来解析用户输入的命令,例如:

bash 复制代码
todo add "学习Go语言"
todo list
todo done 1

main.go

go 复制代码
package main

import (
	"flag"
	"fmt"
	"os"
)

const filename = "todos.json"

func main() {
	// 定义子命令
	addCmd := flag.NewFlagSet("add", flag.ExitOnError)
	listCmd := flag.NewFlagSet("list", flag.ExitOnError)
	doneCmd := flag.NewFlagSet("done", flag.ExitOnError)

	if len(os.Args) < 2 {
		fmt.Println("用法: todo [add|list|done] [参数]")
		return
	}

	// 加载任务
	var todoList ToDoList
	_ = todoList.Load(filename)

	switch os.Args[1] {
	case "add":
		addCmd.Parse(os.Args[2:])
		if addCmd.NArg() < 1 {
			fmt.Println("用法: todo add 任务内容")
			return
		}
		title := addCmd.Arg(0)
		task := Task{ID: len(todoList.Tasks) + 1, Title: title, Done: false}
		todoList.Tasks = append(todoList.Tasks, task)
		_ = todoList.Save(filename)
		fmt.Println("添加任务:", title)

	case "list":
		listCmd.Parse(os.Args[2:])
		fmt.Println("待办事项:")
		for _, task := range todoList.Tasks {
			status := "未完成"
			if task.Done {
				status = "✅ 已完成"
			}
			fmt.Printf("%d. %s [%s]\n", task.ID, task.Title, status)
		}

	case "done":
		doneCmd.Parse(os.Args[2:])
		if doneCmd.NArg() < 1 {
			fmt.Println("用法: todo done 任务编号")
			return
		}
		var id int
		fmt.Sscanf(doneCmd.Arg(0), "%d", &id)
		for i, task := range todoList.Tasks {
			if task.ID == id {
				todoList.Tasks[i].Done = true
				fmt.Println("已完成任务:", task.Title)
				break
			}
		}
		_ = todoList.Save(filename)

	default:
		fmt.Println("未知命令:", os.Args[1])
	}
}

四、运行效果

  1. 添加任务:
bash 复制代码
$ ./todo add "学习 Go"
添加任务: 学习 Go
  1. 查看任务列表:
bash 复制代码
$ ./todo list
待办事项:
1. 学习 Go [未完成]
  1. 完成任务:
bash 复制代码
$ ./todo done 1
已完成任务: 学习 Go
  1. 再次查看:
bash 复制代码
$ ./todo list
待办事项:
1. 学习 Go [✅ 已完成]

数据会自动保存在 todos.json 文件中。


五、总结

这个小工具实现了最基本的 ToDo 功能:

  • 命令行交互 :使用 flag 区分子命令;
  • 本地存储:用 JSON 文件存储任务;
  • 增删改查:支持添加、查看和标记完成。

后续可以扩展的功能包括:

  • 删除任务
  • 支持优先级
  • 任务截止日期提醒
  • 使用 SQLite 或 BoltDB 存储

相关推荐
审判长烧鸡2 小时前
GO错误处理【4】报错即链条
go·异常处理·错误处理
消失的旧时光-19432 小时前
Spring Boot 工程化进阶:统一返回 + 全局异常 + AOP 通用工具包
java·spring boot·后端·aop·自定义注解
追风筝的人er3 小时前
SpringBoot+Vue3 企业考勤如何处理法定假期?节假日方案、调休补班与工作日判断链路拆解
前端·vue.js·后端
金銀銅鐵4 小时前
[git] 如何丢弃对一个文件的改动?
git·后端
橘子海全栈攻城狮4 小时前
【最新源码】养老院系统管理A013
java·spring boot·后端·web安全·微信小程序
smallyoung5 小时前
具有反思能力的 Agentic RAG 实战:用 LangChain4j 实现 CRAG 纠错检索
人工智能·后端
EthanYuan5 小时前
💡RAG实践:从云知识库迁移到PostgreSQL ,并使用PGVector实现向量存储
后端
直奔標竿5 小时前
Java开发者AI转型第二十六课!Spring AI 个人知识库实战(五)——联网搜索增强实战
java·开发语言·人工智能·spring boot·后端·spring
等风来_shy5 小时前
如何写好一个 Skill
后端
ailab6 小时前
研发人员如何写好 AI 提示词:从“问问题”到“驱动研发闭环”
后端