自学内容网 自学内容网

15分钟学 Go 第 37 天:综合复习与小项目

第37天:综合复习与小项目

今天我们将通过完成一个小项目来综合复习之前所学的Go语言知识。本次课程的目标是巩固前面学到的基础与高级概念,涉及Go语言的变量、数据类型、函数、结构体、接口、并发、模块管理等内容。通过一个实战项目,你将学习如何将这些知识应用到实际开发中,并为未来的Go语言开发打下坚实的基础。

我们将开发一个简单的任务管理系统(To-Do List),这个项目的主要功能包括:

  1. 添加任务
  2. 列出所有任务
  3. 标记任务为已完成
  4. 删除任务
  5. 保存和加载任务列表到文件

该项目将涵盖以下内容:

  • Go的数据结构(切片、结构体)
  • 文件读写操作
  • Go并发与同步
  • Go模块化管理
  • 单元测试

一、项目需求分析

1. 功能列表

功能描述
添加任务用户可以添加一个任务到待办事项列表中
列出所有任务列出当前的所有任务,并显示每个任务的状态(完成/未完成)
标记任务为完成用户可以标记某个任务为已完成状态
删除任务用户可以删除某个任务
保存任务列表将任务列表保存到文件中,以便下次运行时加载
加载任务列表启动时从文件加载之前保存的任务列表

2. 项目结构

该项目的代码将遵循模块化设计,方便扩展和维护。目录结构如下:

/todo-app
    /main.go         # 主程序入口
    /todo.go         # 任务结构体及相关操作
    /storage.go      # 任务的保存与加载逻辑
    /todo_test.go    # 单元测试文件
    /README.md       # 项目说明文档

二、设计思路与实现步骤

1. 数据结构设计

任务结构体

首先,我们定义任务的基本信息,每个任务包括以下几个字段:

  • ID:任务的唯一标识
  • 名称:任务的描述
  • 是否完成:表示任务的完成状态
package todo

import "fmt"

// Task 表示一个待办事项
type Task struct {
ID       int    // 任务ID
Name     string // 任务描述
Complete bool   // 是否完成
}

// String 实现 Task 的字符串表示
func (t Task) String() string {
status := "未完成"
if t.Complete {
status = "已完成"
}
return fmt.Sprintf("[%d] %s - %s", t.ID, t.Name, status)
}
任务管理切片

我们使用切片来管理多个任务。任务列表以切片的形式存储,提供添加、删除、标记完成等操作。

package todo

// TaskList 管理任务的列表
type TaskList struct {
Tasks []Task
}

// AddTask 添加新任务
func (tl *TaskList) AddTask(name string) {
task := Task{
ID:       len(tl.Tasks) + 1,
Name:     name,
Complete: false,
}
tl.Tasks = append(tl.Tasks, task)
}

// ListTasks 列出所有任务
func (tl *TaskList) ListTasks() []Task {
return tl.Tasks
}

// CompleteTask 标记任务为完成
func (tl *TaskList) CompleteTask(id int) {
for i, task := range tl.Tasks {
if task.ID == id {
tl.Tasks[i].Complete = true
break
}
}
}

// DeleteTask 删除任务
func (tl *TaskList) DeleteTask(id int) {
for i, task := range tl.Tasks {
if task.ID == id {
tl.Tasks = append(tl.Tasks[:i], tl.Tasks[i+1:]...)
break
}
}
}

2. 文件读写操作

为了保持任务列表的持久性,我们需要实现任务的保存和加载。这里我们使用 encoding/json 包将任务列表序列化为 JSON 格式并写入文件,加载时则反序列化。

package todo

import (
"encoding/json"
"io/ioutil"
"os"
)

// SaveTasks 将任务保存到文件
func (tl *TaskList) SaveTasks(filename string) error {
data, err := json.Marshal(tl.Tasks)
if err != nil {
return err
}
return ioutil.WriteFile(filename, data, 0644)
}

// LoadTasks 从文件加载任务
func (tl *TaskList) LoadTasks(filename string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()

data, err := ioutil.ReadAll(file)
if err != nil {
return err
}

return json.Unmarshal(data, &tl.Tasks)
}

3. 并发与任务操作

为了提高程序的响应速度,我们可以使用Go语言的并发特性,比如在任务加载和保存时使用 Goroutine。

package todo

import (
"log"
"sync"
)

// SaveTasksConcurrently 并发保存任务
func (tl *TaskList) SaveTasksConcurrently(filename string) {
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
if err := tl.SaveTasks(filename); err != nil {
log.Println("任务保存失败:", err)
}
}()
wg.Wait()
}

// LoadTasksConcurrently 并发加载任务
func (tl *TaskList) LoadTasksConcurrently(filename string) {
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
if err := tl.LoadTasks(filename); err != nil {
log.Println("任务加载失败:", err)
}
}()
wg.Wait()
}

4. 用户交互界面

在命令行界面中,我们可以通过菜单方式让用户与任务系统进行交互。以下是命令行界面的简单实现。

package main

import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
"todo-app/todo"
)

func main() {
reader := bufio.NewReader(os.Stdin)
tasks := &todo.TaskList{}
filename := "tasks.json"

// 加载之前保存的任务
tasks.LoadTasks(filename)

for {
fmt.Println("\n=== 任务管理系统 ===")
fmt.Println("1. 添加任务")
fmt.Println("2. 列出所有任务")
fmt.Println("3. 完成任务")
fmt.Println("4. 删除任务")
fmt.Println("5. 保存并退出")

choice, _ := reader.ReadString('\n')
choice = strings.TrimSpace(choice)

switch choice {
case "1":
fmt.Println("请输入任务名称:")
name, _ := reader.ReadString('\n')
name = strings.TrimSpace(name)
tasks.AddTask(name)
fmt.Println("任务已添加!")
case "2":
fmt.Println("当前任务列表:")
for _, task := range tasks.ListTasks() {
fmt.Println(task)
}
case "3":
fmt.Println("请输入要完成的任务ID:")
idInput, _ := reader.ReadString('\n')
id, _ := strconv.Atoi(strings.TrimSpace(idInput))
tasks.CompleteTask(id)
fmt.Println("任务已标记为完成!")
case "4":
fmt.Println("请输入要删除的任务ID:")
idInput, _ := reader.ReadString('\n')
id, _ := strconv.Atoi(strings.TrimSpace(idInput))
tasks.DeleteTask(id)
fmt.Println("任务已删除!")
case "5":
tasks.SaveTasks(filename)
fmt.Println("任务列表已保存。")
return
default:
fmt.Println("无效的选择,请重新输入。")
}
}
}

三、项目功能展示与代码运行流程

1. 任务添加

用户输入任务名称,程序将其添加到任务列表中,并显示所有任务。

2. 任务完成

用户输入任务的ID,程序将其标记为已完成,并更新任务状态。

3. 任务删除

用户输入任务ID,程序删除该任务并显示更新后的任务列表。

4. 保存与加载

程序启动时自动从文件中加载任务列表,退出时保存当前的任务列表到文件中。

5. 并发操作

通过并发方式加载和保存任务,提升程序的响应速度。


四、代码运行流程图

下图展示了整个程序的执行流程:

+----------------------------------+
|           程序启动                |
+----------------------------------+
            |
            v
+-----------------------+          +------------------------+
| 加载任务列表            |----->----| 文件加载成功             |
+-----------------------+          +------------------------+
            |
            v
+-----------------------+
| 显示主菜单              |
+-----------------------+
            |
            v
+-----------------------------------------------+
| 用户选择操作(添加、列出、完成、删除、退出)          |
+-----------------------------------------------+
            |
            v
+-----------------------+
| 执行相应的操作           |
+-----------------------+
            |
            v
+----------------------------------+
| 保存任务并退出程序                  |
+----------------------------------+

五、项目扩展方向

  1. 增加定时提醒功能:可以为每个任务设置截止时间,并在超时后提醒用户。
  2. 增加任务优先级:为任务分配优先级,帮助用户更好地管理待办事项。
  3. 引入REST API:可以将任务管理系统改为Web应用,提供RESTful API接口,便于其他系统集成。

六、总结

通过本次小项目的开发,我们巩固了Go语言的多项核心知识,包括结构体、切片、并发、文件操作以及模块化管理。这个项目展示了如何将Go语言的基本概念应用到实际项目中,并通过命令行界面与用户进行交互。


怎么样今天的内容还满意吗?再次感谢观众老爷的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务自由,还请给个赞,谢谢!


原文地址:https://blog.csdn.net/weixin_40780178/article/details/143473761

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!