在日常工作或学习中,记录待办事项(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])
}
}
四、运行效果
- 添加任务:
bash
$ ./todo add "学习 Go"
添加任务: 学习 Go
- 查看任务列表:
bash
$ ./todo list
待办事项:
1. 学习 Go [未完成]
- 完成任务:
bash
$ ./todo done 1
已完成任务: 学习 Go
- 再次查看:
bash
$ ./todo list
待办事项:
1. 学习 Go [✅ 已完成]
数据会自动保存在 todos.json
文件中。
五、总结
这个小工具实现了最基本的 ToDo 功能:
- 命令行交互 :使用
flag
区分子命令; - 本地存储:用 JSON 文件存储任务;
- 增删改查:支持添加、查看和标记完成。
后续可以扩展的功能包括:
- 删除任务
- 支持优先级
- 任务截止日期提醒
- 使用 SQLite 或 BoltDB 存储