10 KiB
转岗计划 · 第 1 周学习计划(Go 基础语法)
所属阶段:第 1 个月 Go 全栈基础。总纲见同目录
README.md。
目标:一周内掌握 Go 的核心语法,最后用纯标准库写出一个能跑的命令行“任务清单”小程序,为第 2 周用 Gin 写接口打基础。
每天建议投入 1.5 到 2 小时:先看资料 30 分钟,再动手写代码。代码可以让 AI 辅助,但每个文件都要自己能讲清楚每一行在做什么。
参考资料:
- Go 官方教程(中文):https://tour.go-zh.org/
- Go by Example(中文):https://gobyexample-cn.github.io/
- 官方文档:https://go.dev/doc/
最终项目结构
一周结束时,你的练习目录应该长这样:
go-learning/
├── go.mod
├── day1/
│ └── main.go
├── day2/
│ ├── main.go
│ └── calc.go
├── day3/
│ ├── main.go
│ └── collections.go
├── day4/
│ ├── main.go
│ └── task.go
├── day5/
│ ├── main.go
│ ├── storage.go
│ └── errors.go
├── day6/
│ ├── main.go
│ ├── worker.go
│ └── calc_test.go
└── todo/ # 第 7 天的周末小项目
├── go.mod
├── main.go
├── internal/
│ ├── task/
│ │ ├── task.go
│ │ └── task_test.go
│ └── store/
│ └── file_store.go
└── tasks.json # 程序运行后自动生成
第 1 天:环境搭建和第一个程序
学习内容
- 在 Ubuntu 上安装 Go:
sudo apt install golang-go,或从 https://go.dev/dl/ 下载最新版。用go version确认安装成功。 - 编辑器装好 Go 插件(VS Code 或 Cursor 里搜索 “Go” 官方插件)。
- 理解 module(模块)、package(包)、
main函数。 - 变量声明:
var、:=,常量const,基本类型int、float64、string、bool。 fmt.Println、fmt.Printf格式化输出。
要建的文件
go-learning/go.mod:在go-learning目录里运行go mod init go-learning生成。day1/main.go:- 打印 “Hello, Go”。
- 声明你的姓名、工作年限、技术栈(用变量和常量),格式化打印成一段自我介绍。
- 试一下类型转换:把
int转成float64计算平均值。
运行方式:go run ./day1
完成标准:能说清楚 var a int = 1 和 a := 1 的区别,以及为什么 Go 里声明了没用的变量会编译报错。
第 2 天:流程控制和函数
学习内容
if、for(Go 只有for,没有while)、switch。- 函数定义、多返回值、命名返回值。
- 函数作为参数(和 JS 里的回调对比)、匿名函数、闭包。
defer的执行顺序。
要建的文件
day2/calc.go:func Add(a, b int) intfunc Divide(a, b float64) (float64, error):除数为 0 时返回错误。func Apply(nums []int, fn func(int) int) []int:对每个数执行传入的函数,类似 JS 的map。
day2/main.go:- 调用上面三个函数并打印结果。
- 用
for打印 1 到 100 的 FizzBuzz。 - 写一个
defer的例子,观察打印顺序。
运行方式:go run ./day2
完成标准:理解 Go 为什么用“多返回值 + error”而不是 try/catch 来处理错误。
第 3 天:数组、切片和 map
学习内容
- 数组和切片的区别,
make、append、len、cap。 - 切片的底层共享内存问题(这是面试常考点)。
map的增删改查、判断 key 是否存在(v, ok := m[key])。range遍历。
要建的文件
day3/collections.go:func Filter(nums []int, fn func(int) bool) []int:类似 JS 的filter。func Unique(items []string) []string:用 map 给字符串切片去重。func WordCount(text string) map[string]int:统计一段英文里每个单词出现的次数(用strings.Fields)。
day3/main.go:- 调用以上函数并打印结果。
- 写一个例子演示:对一个切片截取子切片后修改元素,原切片也跟着变。
运行方式:go run ./day3
完成标准:能解释 append 什么时候会重新分配底层数组。
第 4 天:结构体、方法和接口(最重要的一天)
学习内容
struct定义、初始化,和 JS 对象、TS 的interface对比。- 方法:值接收者和指针接收者的区别。
- 接口
interface:Go 的接口是隐式实现的,不需要写implements。 - 结构体标签
json:"title"和encoding/json的序列化、反序列化。
要建的文件
day4/task.go:- 定义
Task结构体:ID int、Title string、Done bool、CreatedAt time.Time,并加上 JSON 标签。 - 方法
func (t *Task) MarkDone():把任务标记为完成。 - 方法
func (t Task) String() string:返回类似[x] 1. 学习 Go的文字。 - 定义接口
type Store interface { Add(t Task) error; List() ([]Task, error) }。 - 实现一个
MemoryStore结构体,用切片在内存里存任务,满足Store接口。
- 定义
day4/main.go:- 创建几个任务,存入
MemoryStore,标记其中一个完成,打印列表。 - 把任务列表用
json.MarshalIndent转成 JSON 字符串打印出来。
- 创建几个任务,存入
运行方式:go run ./day4
完成标准:能说清楚什么时候用指针接收者,以及“接口隐式实现”带来的好处。
第 5 天:错误处理和文件读写
学习内容
error接口、errors.New、fmt.Errorf搭配%w包装错误。errors.Is、errors.As判断错误类型。- 自定义错误类型。
os.ReadFile、os.WriteFile读写文件。panic和recover(了解即可,业务代码里尽量不用)。
要建的文件
day5/errors.go:- 定义
var ErrNotFound = errors.New("task not found")。 - 定义自定义错误
ValidationError结构体,包含字段名和原因,实现Error()方法。
- 定义
day5/storage.go:func SaveTasks(path string, tasks []Task) error:把任务列表写成 JSON 文件。func LoadTasks(path string) ([]Task, error):从 JSON 文件读取;文件不存在时返回空列表而不是报错。func FindTask(tasks []Task, id int) (Task, error):找不到时返回包装后的ErrNotFound。
day5/main.go:- 保存任务到
tasks.json,再读回来打印。 - 查找一个不存在的 ID,用
errors.Is判断是不是ErrNotFound。 - 标题为空时返回
ValidationError,用errors.As取出字段名打印。
- 保存任务到
运行方式:go run ./day5
完成标准:习惯每个可能出错的调用后面都写 if err != nil,并给错误加上上下文信息。
第 6 天:并发入门和单元测试
学习内容
goroutine:用go关键字启动并发任务。channel:在 goroutine 之间传数据,有缓冲和无缓冲的区别。sync.WaitGroup等待一组任务完成,sync.Mutex保护共享数据。- 用
go test写单元测试,表格驱动测试的写法。
要建的文件
day6/worker.go:func FetchAll(urls []string) map[string]int:并发请求多个网址(用net/http),返回每个网址的 HTTP 状态码。用WaitGroup等待全部完成,用Mutex保护结果 map。func Pipeline(nums []int) <-chan int:用 channel 写一个“生成数字,然后平方”的流水线。
day6/main.go:调用FetchAll请求 3 到 5 个网站,打印结果和总耗时,对比顺序请求的耗时。day6/calc_test.go:把第 2 天的Add和Divide复制到day6里,写表格驱动测试,覆盖正常情况和除数为 0 的情况。
运行方式:go run ./day6 和 go test ./day6 -v
完成标准:能解释 goroutine 和 JS 的 Promise/async 有什么不同。
第 7 天:周末小项目 · 命令行任务清单
把这周学的东西串起来,做一个能实际使用的命令行工具。
功能
go run . add "学习 Gin":添加任务。go run . list:列出所有任务。go run . done 1:把 1 号任务标记为完成。go run . delete 1:删除 1 号任务。- 数据保存在
tasks.json,程序重启后还在。
要建的文件
todo/go.mod:在todo目录运行go mod init todo。todo/internal/task/task.go:Task结构体和它的方法(来自第 4 天),加上Validate()方法校验标题不能为空。todo/internal/task/task_test.go:测试MarkDone和Validate。todo/internal/store/file_store.go:FileStore结构体,实现Add、List、Done、Delete,内部用 JSON 文件持久化(来自第 5 天),找不到任务时返回ErrNotFound。todo/main.go:用os.Args解析命令,调用FileStore,出错时打印友好的提示并以非 0 状态码退出。
运行方式:在 todo 目录下运行 go run . list,测试用 go test ./...
完成标准
- 四个命令都能正常使用,重启后数据不丢。
go test ./...全部通过。go vet ./...没有警告,代码用gofmt格式化过。- 给
todo写一个简单的 README,提交并推送到zhuangang仓库(路径go-learning/todo/),这是你的第一个 Go 作品。以后整理作品集时可以再单独同步到 GitHub。
本周自查清单
- 能用
:=和var声明变量,知道区别 - 会写多返回值函数,并正确处理
error - 理解切片和 map 的常见用法与坑
- 会定义结构体、方法和接口
- 会读写 JSON 文件
- 会用 goroutine、channel、WaitGroup 写简单并发
- 会写表格驱动的单元测试
- 完成
todo项目并推送到zhuangang仓库 - 在总纲
README.md的进度记录里勾掉第 1 周
下周预告:第 2 周用 Gin 把这个任务清单改造成 HTTP 接口,前端用你熟悉的 React 或 Vue 接上去。