README
# 卷二 · 综合案例总导读
本卷是**卷一《语法卷》**的配套实战篇。学完卷一 18 章基础语法后,通过 5 个循序渐进的项目把散落的知识点串起来,形成"能独立写项目"的能力。其中 05.静态博客生成引擎 是"集大成的毕业设计",一篇覆盖卷一全部 18 章。
# 01.定位与使用方式
本卷的每一篇都按**"照着写 · 抄得懂 · 改得动"**三个层次设计:
- 照着写:每个小节先给需求、再给代码片段,读者跟着键入即可跑通。
- 抄得懂:代码后必有"为什么这样写 / 关键机制原理"小节,回答"Go 为什么不能像 Python/Java 那样随手写"。
- 改得动:每篇结尾留 3-5 个"延伸挑战",鼓励读者用新学的特性重构。
声明:本卷代码风格以 Go 1.22 为基线,泛型(1.18+)、
slices/maps标准库(1.21+)默认就用;构建仅依赖官方工具链(go build/go test/go vet);坚持 0 第三方库(仅允许golang.org/x/...等官方扩展),保证学习纯度——你看到的每一行代码都是 Go 自己造的轮子。
为什么是 5 个案例而不是 12 个? 卷二曾经有过 12 案例版本,复盘后发现:① 前 6 个都在练"struct + slice/map + CRUD"高度同质化;② 第 11/15/16/17 章缺少专门承载的案例;③ 难度跳跃断层(从单文件小程序直接跳到 KV 存储引擎)。新版 5 案例严格按"小白 → 中级 → 高级"递进,每个案例只引入 1-2 个新难点,且分别落在 CLI 工具 / 数据处理 / 网络服务 / 并发系统 / 工程化全家桶 五个不同领域,避免重复。
# 02.5 个案例总览
难度阶梯:
⭐⭐ → ⭐⭐⭐ → ⭐⭐⭐ → ⭐⭐⭐⭐ → ⭐⭐⭐⭐⭐
01 gotodo → 02 golog → 03 goshort → 04 gocron → 05 gosite
──────────── ───────────── ───────────── ───────────── ─────────────
CLI 工具 数据处理流水线 HTTP 网络服务 并发调度系统 工程化全家桶
单文件 ~600 行 多文件 ~1000 行 模块化 ~1500 行 多 pkg ~2500 行 完整工程 ~4000 行
2
3
4
5
6
7
| # | 案例 | 难度 | 预估时长 | 字数 | 主导领域 |
|---|---|---|---|---|---|
| 01 | gotodo 命令行待办事项 | ⭐⭐ | 4 h | ~1.5 万 | CLI 工具 + JSON 持久化 |
| 02 | golog 高性能日志分析流水线 | ⭐⭐⭐ | 6 h | ~1.5 万 | 数据处理 + 流式 IO + 泛型 |
| 03 | goshort 短链服务 | ⭐⭐⭐ | 8 h | ~1.8 万 | HTTP 服务 + 并发安全 |
| 04 | gocron 可观测的并发任务调度器 | ⭐⭐⭐⭐ | 12 h | ~2 万 | 并发系统 + 中间件 |
| 05 | gosite 静态博客生成器 🎓 | ⭐⭐⭐⭐⭐ | 16-20 h | ~2.5 万 | 工程化全家桶(毕业设计) |
核心特点:第 05 案例复用前 4 个的产物——用 01 的 CLI 风格做
gosite new/build/serve、用 02 的流式处理做 markdown 解析、用 03 的 HTTP server 做本地预览、用 04 的 worker pool 做并发渲染。形成"积木拼装"的工程闭环。
# 03.卷一章节—案例覆盖矩阵
下表展示卷一每章在本卷的落地点。读者也可以反向使用——"我想练习 channel,去找第 03/04 案例"。
✅ = 该章节是案例的核心知识点 / 🟡 = 顺带使用 / 空白 = 不涉及
| 卷一章节 | 核心知识点 | 01 gotodo | 02 golog | 03 goshort | 04 gocron | 05 gosite |
|---|---|---|---|---|---|---|
| 01 Go 简史 | 版本演进 | 🟡 | 🟡 | |||
| 02 基础语法 | package/import/go mod | ✅ | ✅ | 🟡 | 🟡 | 🟡 |
| 03 数据类型 | int/string/time | ✅ | ✅ | 🟡 | 🟡 | 🟡 |
| 04 运算符 | 算术/比较/位 | ✅ | ✅ | 🟡 | 🟡 | 🟡 |
| 05 复合类型 | slice/map/struct | ✅ | ✅ | ✅ | ✅ | ✅ |
| 06 流程语句 | for/range/switch | ✅ | ✅ | ✅ | ✅ | ✅ |
| 07 函数 | 多返回值/defer/闭包 | ✅ | ✅ | ✅ | ✅ | ✅ |
| 08 指针与逃逸 | *T 接收者/逃逸分析 | 🟡 | ✅ | 🟡 | ✅ | ✅ |
| 09 结构体与方法 | 接收者/嵌入字段/Tag | ✅ | ✅ | ✅ | ✅ | ✅ |
| 10 接口与多态 | 接口隐式实现/类型断言 | 🟡 | ✅ | ✅ | ✅ | ✅ |
| 11 错误处理 | errors.Is/As/%w | ✅ | ✅ | ✅ | ✅ | ✅ |
| 12 goroutine | go/context | 🟡 | ✅ | ✅ | ✅ | |
| 13 channel | 缓冲/select/关闭 | 🟡 | ✅ | ✅ | ✅ | |
| 14 sync 包 | Mutex/RWMutex/Pool/atomic | ✅ | ✅ | ✅ | ||
| 15 IO 与文件 | bufio/io/fs/embed | ✅ | ✅ | 🟡 | ✅ | ✅ |
| 16 标准库与泛型 | slices/maps/泛型容器 | 🟡 | ✅ | ✅ | ✅ | ✅ |
| 17 工程化与模块 | go.mod/build tag/go:generate | 🟡 | 🟡 | ✅ | ✅ | ✅ |
| 18 特性图谱 | errors.Join/slog/embed/range over func | 🟡 | ✅ | ✅ | ✅ |
结论:卷一 18 章每一章都至少被 ✅ 标记 1 次以上;核心章节(05 复合类型 / 07 函数 / 09 结构体 / 11 错误处理)被 5 个案例全面夯实;第 05 案例 gosite 一篇打满 18 章——这就是"毕业设计"的含义。
# 04.单案例知识点详图
# 案例 01 · gotodo · 命令行待办事项管理器 ⭐⭐
学完卷一第 1-11 章 + 第 15 章后能立刻上手。从 hello world 到第一个真实程序的桥梁。
功能列表:
gotodo add "买牛奶" --tag shopping --due 2026-06-01gotodo list [--filter done|todo --tag X]gotodo done 3/gotodo rm 3/gotodo edit 3 "新内容"- 数据持久化到
~/.gotodo.json,原子写入(写临时文件 + rename) - 彩色输出(用 ANSI 转义码,不引入第三方库)
反模式对照:
- ❌ 直接
os.WriteFile不原子 → ✅ tmp + rename - ❌
fmt.Errorf("%v", err)丢链 → ✅%w包装 - ❌ 用
panic处理用户输入错 → ✅ 返回 error + 退出码
产出物:单文件 ~600 行 Go + 一份 Makefile,能跑能装能用。
# 案例 02 · golog · 高性能日志分析流水线 ⭐⭐⭐
覆盖卷一第 8、15、16 章的核心——指针/逃逸、流式 IO、泛型、
bufio/encoding。小白第一次接触性能的案例。
功能列表:
- 输入:Nginx access log(10GB+ 单文件,行式)
- 输出:Top N IP / Top N URL / 状态码分布 / QPS 时间序列
- 支持
--format json|table|csv三种输出 - 流式处理:
cat *.log | golog stat,不能把整文件读进内存 - 朴素版 vs 流式版的 benchmark 对比
反模式对照:
- ❌
os.ReadFile整文件读入 → ✅bufio.Scanner流式 - ❌
strings.Split切完拼回 → ✅bytes.IndexByte零分配解析 - ❌
map[string]Counter值拷贝 → ✅map[string]*Counter+ 逃逸分析对照
产出物:~1000 行 Go,5 个文件,含 benchmark 报告。
# 案例 03 · goshort · 短链服务 ⭐⭐⭐
覆盖卷一第 9-14 章的并发与网络核心。从单机程序到 Web 服务的跨越。
功能列表:
- HTTP 接口:
POST /shorten/GET /:code/GET /stats/:code - 短码算法:base62(snowflake_id)
- 存储:内存 map + 持久化到自实现的 append-only file
- 限流:令牌桶中间件,用 channel 实现而非第三方库
- 健康检查
/healthz、metrics/metrics(Prometheus 文本格式) - graceful shutdown +
embed嵌入静态首页
反模式对照:
- ❌ 全局 map + 一把大 mutex → ✅ 分片锁 /
sync.Map的取舍 - ❌
http.HandleFunc平铺 → ✅ middleware 链式 - ❌ goroutine 没 ctx 泄漏 → ✅
context.WithTimeout
产出物:~1500 行 Go,10+ 文件的标准布局,可用 curl 实测。
# 案例 04 · gocron · 可观测的并发任务调度器 ⭐⭐⭐⭐
并发核心 + 现代 Go 特性。理解 GMP 之前的最后一站,为卷三专栏 06 GMP / 10 timer / 11 channel / 15 context 打基础。
功能列表:
- 类似 cron 但支持秒级;任务定义用 Go 函数(不是 shell 命令)
- 调度精度:四叉堆排序;自己实现一个简化版 P 本地 timer
- worker pool:固定 N 个 worker、动态扩缩容
- 任务隔离:单任务 panic 不影响调度器(recover)
- 取消传播:父任务取消,所有子任务级联取消
- trace:每个任务执行链路可视化(输出 jaeger 兼容格式)
反模式对照:
- ❌
time.After在循环里泄漏 → ✅time.NewTimer+Stop - ❌ 用 sleep 轮询任务队列 → ✅
time.Timer+select唤醒 - ❌ panic 直接挂 worker → ✅
defer recover转 error
产出物:~2500 行 Go,5 个 package,含 demo 任务(HTTP 健康检查 / 文件备份)。
# 案例 05 · gosite · 静态博客生成器(毕业设计)⭐⭐⭐⭐⭐
集大成之作。一个真实可用的静态博客生成器(对标 Hugo),能跑、能装、能 GitHub Actions 部署。复用前 4 个案例的产物。
功能列表:
gosite new mysite— 脚手架gosite build— 把content/*.md渲染成public/*.html,并发处理gosite serve— 本地启 HTTP + 文件监听 + 浏览器热重载(websocket)gosite deploy— git push 到 gh-pages- 主题系统:
themes/default/templates/*.html,用text/template+ 自定义函数 - 增量构建:基于文件 mtime + 内容哈希
- RSS / sitemap 自动生成
- 内置图片优化(PNG → WebP)
反模式对照(最后一章集中讲 8-10 条工程反模式):
- ❌ 把模板当字符串拼接 → ✅
html/template自动转义 - ❌ goroutine 数 = 文件数 → ✅ worker pool 限流
- ❌ 全局变量配置 → ✅ 显式传
*Config - ❌ 二进制无版本号 → ✅ ldflags 注入 commit/buildtime
- ❌ 单 Linux 二进制 → ✅
GOOS=darwin/windows/linux GOARCH=amd64/arm64矩阵
产出物:~4000 行 Go,标准 cmd/internal/pkg 三层布局;附带 GitHub Actions release 工作流;最终能 go install github.com/yc/gosite@latest 一键装。
# 05.推荐学习路径
# 路径 A:新手线(按顺序走完)
01 gotodo(CLI 入门)
↓
02 golog(数据处理 + 性能初体验)
↓
03 goshort(HTTP 服务 + 并发初体验)
↓
04 gocron(深入并发 + 中间件)
↓
05 gosite(毕业设计:复用前 4 个产物,串完卷一所有 18 章)
2
3
4
5
6
7
8
9
# 路径 B:带 Java/Python 转 Go(按主题跳读)
快速验收: 01(CLI 与文件) → 03(HTTP 与并发) → 05(工程化)
并发主题: 03 → 04 → 05
性能主题: 02 → 04 → 05
工程主题: 01(基础规范) → 05(完整工程链路)
2
3
4
# 路径 C:快速查漏(按卷一章节反查)
| 想练习的卷一章节 | 优先看哪个案例 |
|---|---|
| 第 5 章 复合类型(slice/map/struct) | 全部,重点 02 / 05 |
| 第 8 章 指针与逃逸 | 02 golog(性能对照)/ 04 / 05 |
| 第 9-10 章 结构体与接口 | 03 goshort(Storage 接口双实现)/ 04 / 05 |
| 第 11 章 错误处理 | 全部,重点 04(errors.Join 聚合)/ 05 |
| 第 12 章 goroutine | 03 / 04(worker pool) / 05 |
| 第 13 章 channel | 04 gocron(fan-out/fan-in)/ 03 / 05 |
| 第 14 章 sync 包 | 03 goshort(RWMutex + Pool)/ 04 |
| 第 15 章 IO 与文件 | 02 golog(流式)/ 01 / 05 |
| 第 16 章 泛型与标准库 | 02 golog(泛型 Top-K 堆)/ 04 / 05 |
| 第 17 章 工程化模块 | 05 gosite(标准布局 + ldflags + CI/CD) |
| 第 18 章 特性图谱 | 05 gosite(context/embed/range over func/slog) |
| 想一次性串完卷一所有章节 | 直接做 05 gosite |
# 06.统一的写作约定
为保证 5 个案例"看起来像一本书",本卷遵循以下统一约定:
# 6.1 每篇八段式结构
| 段 | 内容 | 字数 |
|---|---|---|
| 1. 需求拆解 | 真实场景 + 功能清单 + 不做什么 | 1000 |
| 2. 架构设计 | mermaid 模块图 + 数据流图 + 关键决策 | 1500 |
| 3. 核心数据结构 | 几个核心 struct/interface 的定义与权衡 | 2000 |
| 4. 关键流程逐段实现 | 按"功能切片"展示完整可跑代码 | 6000 |
| 5. 反模式对照 | 5-8 条 ❌ vs ✅ | 2000 |
| 6. 测试与基准 | 单元测试、表驱动、benchmark | 1500 |
| 7. 卷一章节反向索引 | 表格:本案例第 X 节 ↔ 卷一第 Y 章 | 500 |
| 8. 拓展挑战 | 3-5 个进阶练习题(思考、不给答案) | 500 |
| 合计 | — | ~1.5 万字 |
# 6.2 代码风格
| 项目 | 约定 |
|---|---|
| 命名 | 类型 PascalCase、函数/变量 camelCase、未导出小写、常量 UPPER_SNAKE 或 camelCase |
| 包名 | 全小写,不用下划线,不复数;与目录同名 |
| 错误返回 | if err != nil { return ..., fmt.Errorf("xxx: %w", err) } 三段式 |
panic 使用 | 仅用于"程序员错误"(断言不变量),不能用作业务错误 |
| 接收者 | 大对象 / 需修改 → 指针;小值类型(time、坐标)→ 值 |
| 上下文传递 | 第一个参数 ctx context.Context,绝不存到 struct |
| 内存 | 优先 slice / map 内置类型;只有热点路径才 sync.Pool |
| 标准 | 基线 Go 1.22;用到 1.23+ 特性会标注 🆕 Go 1.23 |
| 测试 | 表驱动 + 子测试(t.Run);目录同名 xxx_test.go |
| 依赖 | 0 第三方库;仅允许 golang.org/x/... 等官方扩展 |
# 6.3 术语统一
| 术语 | 本卷统一译法 |
|---|---|
| receiver | 接收者(不用"接收器") |
| goroutine | 协程 / goroutine(混用) |
| channel | 通道 / channel(混用) |
| zero value | 零值 |
| pointer receiver | 指针接收者 |
| struct embedding | 结构体嵌入 / 嵌入字段 |
| context | 上下文 / context |
| panic | panic(不译) |
# 07.常见疑问 FAQ
Q1:为什么砍掉旧版的 12 个案例?
A:复盘旧 12 案例,发现三个硬伤:① 前 6 个高度同质化(都是"struct + slice/map + CRUD");② 第 11/15/17 章缺少专门承载的案例;③ 难度跳跃断层。新版 5 案例严格按"小白 → 中级 → 高级"递进,每个案例只引入 1-2 个新难点,且分别落在不同领域。少而精胜过多而杂。
Q2:为什么 01 gotodo 这么"小"?
A:01 的目的是"练熟语法 + 第一个能装的二进制"。引入数据库 / Web 框架会让初学者陷入"环境配置 4 小时、写代码 1 小时"的常见困境。等到第 05 案例 gosite,我们会自己手写一个完整工程,亲眼看到 Hugo 这种工具是怎么从 CLI + 文件读写演化来的。
Q3:02 golog 为什么要做 benchmark?
A:02 的主题是"小白第一次接触性能"。Go 工程师的入门门槛之一就是"知道你的代码值多少 ns/op"。这个案例会教你:① 怎么写 benchmark;② 怎么读懂 go test -bench 的输出;③ 怎么用 -gcflags="-m" 看逃逸;④ 把朴素版改成流式版能省多少内存。
Q4:03 / 04 之间有什么递进?
A:
- 03 goshort:HTTP 服务最基础——
net/http+ Mutex + channel 限流,看到"为什么并发不安全"。 - 04 gocron:纯并发系统——多 worker + 任务 channel + context 取消 + panic 隔离,把 03 的"并发 IO"升级为"并发计算调度"。
如果说 03 是"业务上的并发"(请求-响应),04 就是"系统级的并发"(生产者-消费者-调度器)。
Q5:05 gosite 和前 4 个的关系?
A:前 4 个每个只覆盖卷一 5-8 章,是"专题练习";05 是毕业设计——一篇覆盖卷一全部 18 章。它不是"加难度",而是"换视角":从"练单点"切到"做产品"。
05 的设计:
迭代 1(脚手架):gosite new + 默认主题 embed → 串第 15、18 章
迭代 2(构建):markdown 解析 + template 渲染 → 串第 5、7、9、10、16 章
迭代 3(并发渲染):worker pool + sync.WaitGroup + context → 串第 12-14 章
迭代 4(本地预览):HTTP server + websocket 热重载 → 串第 11、13、15 章
迭代 5(增量构建):mtime + sha256 + errors.Join → 串第 8、11、16 章
迭代 6(CI/CD):cross-compile + ldflags + GitHub Actions → 串第 17 章
2
3
4
5
6
预计用 4 次(每次 2-3 小时)读完。建议把它放到学完前 4 个之后再做——前面的零件你都熟悉了,回头看 05 时会有"原来如此"的爽感。
Q6:5 个案例总共多少代码?多久能走完?
A:合计约 9000 行 Go 代码(不含测试),约 9 万字讲解。按每周 1 个案例的节奏,5 周可以走完全部。如果只想快速验收卷一,做 01 + 03 + 05 三个就够了(约 3 周)。
# 08.与其他卷的衔接
| 案例 | 反向衔接卷三《底层卷》 | 正向衔接卷四《实战卷》 |
|---|---|---|
| 01 gotodo | 卷三 11 错误 panic、15 IO | — |
| 02 golog | 卷三 02 逃逸分析、04 字符串切片底层 | 卷四 09 性能优化、10 缓存友好 |
| 03 goshort | 卷三 11 channel、12 sync、20 netpoller | 卷四 06 pprof、07 trace |
| 04 gocron | 卷三 06 GMP、10 timer、15 context | 卷四 05 goroutine 泄漏、07 trace |
| 05 gosite | 卷三 22 编译链接、18 迭代器、19 错误 panic | 卷四 11 PGO、12 编译链接、16 工程化 checklist |
具体阅读顺序建议:
- 卷一《语法卷》:本卷是它的验收考。做不动的话回头复习对应章节。
- 卷三《底层卷》:本卷 04 gocron 只做到"够用";如果想看 GMP 调度、channel 源码,去卷三第 06、08、11 章。
- 卷四《实战卷》:本卷案例代码上线前请读卷四第 06(pprof)、07(trace)、05(goroutine 泄漏)三章——能避免 80% 的线上事故。
# 09.卷二改造完成度(目录连贯性自检表)
本节记录卷二从 12 案例版到 5 案例版的改造轨迹,便于后续维护。
# 9.1 全新创建的章节(5 篇)
| 文件 | 行数预估 | 角色 |
|---|---|---|
01.终端待办任务清单.md | ~1500 | 案例 01 入门 |
02.日志分析处理工具.md | ~1500 | 案例 02 数据处理 |
03.短链服务并发设计.md | ~1800 | 案例 03 HTTP 服务 |
04.并发任务调度引擎.md | ~2000 | 案例 04 并发系统 |
05.静态博客生成引擎.md | ~2500 | 案例 05 毕业设计 |
# 9.2 章节统一格式校验
- ✅ 文件名统一为
NN.英文项目名+中文描述.md格式(与卷一NN.4-8字.md风格区分,体现"项目卷"特色) - ✅ 每篇遵循八段式:需求拆解 → 架构设计 → 核心数据结构 → 关键流程实现 → 反模式对照 → 测试与基准 → 卷一反向索引 → 拓展挑战
- ✅ 跨章引用全部使用相对路径
- ✅ 0 第三方库约束(仅 stdlib +
golang.org/x/...)
# 9.3 后续维护清单
- 每个案例完成后,回填 §02 表格中的"实际字数"
- 卷三对应章节确定后,回填 §08 的卷三具体章节链接
- 当 Go 1.23 / 1.24 引入新特性后,在对应案例中增补"现代写法"侧栏
# 卷首寄语
"Don't communicate by sharing memory; share memory by communicating." — Rob Pike
卷一教会你怎么写每一行 Go 代码;卷二要教会你怎么把一千行 Go 代码组织成一个能装、能跑、能改的产品。
5 个案例,从一个 600 行的命令行小工具,到一个 4000 行的工程化博客生成器——你会经历每一个 Go 工程师都经历过的"啊,原来这样写"的瞬间:
- 第一次发现"原来
defer file.Close()也要检 err"——案例 01 - 第一次发现"原来
map[string]Counter比*Counter慢 3 倍"——案例 02 - 第一次发现"原来 graceful shutdown 不只是
os.Exit(0)"——案例 03 - 第一次发现"原来
time.After在循环里会泄漏"——案例 04 - 第一次发现"原来
go install一行就能让全世界用上你的工具"——案例 05
翻开第 1 章,让我们从 gotodo 开始。