
Go 1.16 发布于 2021-02-16。这一版对日常开发影响很大：`//go:embed` 让静态资源嵌入成为官方能力，`io/fs` 把文件系统抽象推到标准库层面。

源码侧 `api/go1.16.txt` 有 8526 条公开 API 增量，公开标准库目录新增 `embed`、`go/build/constraint`、`io/fs`、`runtime/metrics`、`testing/fstest`。

## 主要变化

### 1. `//go:embed` 成为官方资源嵌入方案

`//go:embed` 让静态文件、目录和 glob 匹配结果可以在编译期进入二进制。它适合嵌入模板、默认配置、前端静态资源和测试数据。

```go
import "embed"

//go:embed templates/*.html
var templates embed.FS
```

它的行为由编译器处理：匹配失败会在编译期报错，文件内容成为二进制的一部分。相比第三方打包工具，它不需要额外生成 Go 文件，也不需要在运行时依赖外部文件路径。

### 2. `io/fs` 建立统一文件系统接口

`io/fs` 定义了 `fs.FS`、`fs.File`、`fs.ReadDirFile` 等接口。`embed.FS`、`os.DirFS`、测试文件系统和自定义只读文件系统都可以用同一套抽象表达。

```go
func LoadConfig(fsys fs.FS, name string) ([]byte, error) {
    return fs.ReadFile(fsys, name)
}
```

这能简化库设计：函数不必只接收本地路径，也不必自己定义一套文件系统接口。生产环境可以传 `os.DirFS`，嵌入资源可以传 `embed.FS`，测试可以传 `fstest.MapFS`。

### 3. 模块模式成为默认工作方式

Go 1.16 默认启用模块模式。`go.mod` 不再只是新项目选项，而是 Go 命令解析依赖、版本和包边界的默认入口。GOPATH 仍然存在，但它的角色更多是兼容旧工作流和缓存目录。

`go env GO111MODULE` 为空时，Go 命令默认按模块模式工作。包加载、`go list`、`go test`、`go build` 都围绕 `go.mod` 展开。模块路径、版本选择和校验数据库因此成为 Go 工程的默认规则。

### 4. `io/ioutil` 功能回到更明确的包

`io/ioutil` 被标记为废弃，不是因为功能消失，而是因为这些函数被放回更准确的位置：读写文件在 `os`，读流在 `io`，临时文件也在 `os`。新 API 的命名更直接，也减少了“ioutil 到底管什么”的歧义。

对应关系很直接：

- `ioutil.ReadAll` 对应 `io.ReadAll`。
- `ioutil.ReadFile` 对应 `os.ReadFile`。
- `ioutil.WriteFile` 对应 `os.WriteFile`。
- `ioutil.ReadDir` 对应 `os.ReadDir`。
- `ioutil.TempFile`、`TempDir` 对应 `os.CreateTemp`、`os.MkdirTemp`。

## 语言与规范

严格说 Go 1.16 没有新语法，但新增编译器指令 `//go:embed`。它需要导入 `embed` 包，并可把文件内容嵌入为 `string`、`[]byte` 或 `embed.FS`。

## 工具链与运行时

Go Modules 默认启用，这是依赖管理历史上的重要节点。`go get`、`go test`、`go list`、`-overlay`、`GOVCS` 等能力都有变化。`GOVCS` 尤其重要，它让组织可以限制模块下载时允许使用的版本控制系统。

运行时新增 `runtime/metrics`，提供更结构化、更稳定的运行时指标接口，适合监控系统采集。

`runtime/metrics` 的指标名带单位和语义，例如堆对象、GC 周期、调度信息等。相比解析 `runtime.MemStats` 的具体字段，它更适合长期演进：新增指标不会破坏旧代码，监控系统也能按名称采集。

## 标准库与新增包

新增公开包：

- `embed`：静态资源嵌入。
- `io/fs`：只读文件系统抽象。
- `testing/fstest`：测试 `fs.FS` 实现。
- `runtime/metrics`：运行时指标。
- `go/build/constraint`：解析构建约束。

重要变化还包括 `io/ioutil` 废弃，建议改用 `io.ReadAll`、`os.ReadFile`、`os.WriteFile`、`os.ReadDir` 等替代 API。

## 小版本特殊变化

Go 1.16 系列共有 15 个小版本。由于这一版引入 `embed`、`io/fs`、模块默认启用和 `runtime/metrics`，小版本里能看到不少文件格式、HTTP 和工具链修复。

这一系列的安全修复很适合和 Go 1.16 的文件系统能力一起看。`archive/zip`、`io/fs`、`debug/macho`、`debug/pe` 都和“读取外部文件格式”有关，风险通常来自路径、长度、偏移和格式畸形输入。`html/template` 涉及自动转义，问题可能导致模板上下文判断错误，从而产生注入风险。`net/http`、`net/http/httputil` 是服务端和代理入口。`misc/wasm` 的修复说明 Wasm 端口也进入了安全维护范围。

- `go1.16.1` 修复 `archive/zip` 和 `encoding/xml` 安全问题。
- `go1.16.4`、`go1.16.5`、`go1.16.7` 都包含 `net/http` 或 `net/http/httputil` 安全/缺陷修复。
- `go1.16.8` 修复 `archive/zip` 安全问题，并涉及 `html/template`、`runtime/pprof`。
- `go1.16.9` 涉及 linker 和 `misc/wasm` 安全修复，和 Go 1.11 引入的 Wasm 支持线索相连。
- `go1.16.10` 修复 `archive/zip` 和 `debug/macho` 安全问题。
- `go1.16.14` 安全修复覆盖 `go` 命令、`crypto/elliptic`、`math/big`，同时修 compiler、linker、runtime、`debug/macho`、`debug/pe`、testing 相关包。
- `go1.16.15` 修复 `regexp/syntax` 安全问题。

## 参考

- [Go 1.16 Release Notes](https://go.dev/doc/go1.16)
- [Go Release History](https://go.dev/doc/devel/release)
- [Go 1.16 source tag](https://go.googlesource.com/go/+/refs/tags/go1.16)
- [api/go1.16.txt](https://go.googlesource.com/go/+/refs/tags/go1.16/api/go1.16.txt)

