在 Go 1.27.1 里复现并行子测试的循环变量捕获问题:同一份测试代码,go.mod 写 go 1.21 时两个子测试看到的是最后一个用例的名字(3 个里只有 1 个通过),写 go 1.22 时全部通过;子测试名的转义规则(空格→_、重名→#01、空串→#00、斜杠保留);-run 的斜杠分隔与正则;-parallel 限制并行度。
在 Go 1.27.1 里实测 testing/synctest:TTL 一小时的缓存,测试里过了 1h0m1s 却耗时 0.00 秒(真实时钟的 300 ms TTL 版本要 0.35 秒);每秒一次的轮询在超时 10.001 秒内确定地调用 10 次;synctest.Wait 确保后台 goroutine 已执行完;所有 goroutine 阻塞又没有定时器时报 deadlock,根 goroutine 退出时有泄漏的 goroutine 也会 panic。
在 Go 1.27.1 里验证 go test 缓存:没有包参数的 go test 根本不缓存;go test . 第 2 次直接 (cached),-count=1 强制重跑;源码任何改动、-race 会换测试二进制;-short、-v、-timeout 有各自的缓存条目,-count=2 不缓存;只有读过的环境变量变化才失效;读模块内的文件会被跟踪,模块外的文件改了结果仍是旧的;依赖时间的测试结果会被冻住。
在 Go 1.27.1 里实测覆盖率:17 个语句里 8 个被覆盖(47.1%);覆盖率文件按“块”记录起止行列、语句数和计数;set/count/atomic 三种模式的计数含义;紧循环里插桩的开销 set 2.33 倍、count 6.34 倍、atomic 26.41 倍;go build -cover 配合 GOCOVERDIR 让普通程序也能收集覆盖率。
在 Go 1.27.1 里实测 go vet:一个故意写了十几类问题的文件被报告了 16 条(来自 13 个检查器)(printf、copylocks、lostcancel、shift、stringintconv、httpresponse、waitgroup、unreachable 等);vet 共有 35 个检查器;go test 自带的 vet 只跑 11 个高置信度的检查,所以 copylocks 问题能通过 go test 却会被 go vet 拦下。
在 Go 1.27.1 里实测 text/template 的求值规则:管道把结果作为后一个命令的最后一个参数(3 | printf "%d-%d" 1 得到 1-3);:= 与 = 的作用域差别;map 缺 key 默认输出 <no value>,missingkey=error 才报错;空字符串、0、nil、空 slice 为假,or 会短路;FuncMap 必须在 Parse 之前注册,函数返回 error 会中断执行;已解析模板 Execute 612 ns,每次都 Parse 要 3474 ns。
在 Go 1.27.1 里实测 html/template 的上下文感知转义:同一个值放在 HTML 文本、属性、URL、JavaScript、CSS、注释里被转义成不同形式(危险协议变成 #ZgotmplZ,JS 值编码成字符串或 JSON,< 变成 \u003c);template.HTML / template.URL 会绕过转义;{{if}} 分支上下文不一致时 Execute 直接报错;Execute 之后不能再 Parse。
在 Go 1.27.1 里实测 encoding/gob:同一个 Encoder 连续编码,第一条消息 51 字节(含类型定义),之后每条只有 11 字节,每次新建 Encoder 则每条都是 51 字节;字段按名字匹配、多出的字段被忽略、类型变了才报错;接口字段必须 Register;复用 Encoder/Decoder 时编码 347 ns、解码 619 ns/条,比 JSON 快,每次新建则慢 3–9 倍。
在 Go 1.27.1 里实测 hash/maphash:同一个字符串在三个进程里的哈希值各不相同(种子随进程随机),同一进程内稳定,分段写入与一次性计算相同,Comparable 可以哈希结构体;16 万个键分到 16 个桶几乎均匀;1 KiB 输入上 maphash 77 ns,FNV-1a 1176 ns;内置 map 的遍历起点也因 map 而异。
在 Docker Engine 29.8.2(BuildKit)里实测构建上下文:目录里有 50 MiB 的无关文件,Dockerfile 只 COPY 一个小文件时只传输 40 B(564 ms),COPY . 时传输 52.44 MB(1923 ms);再构建一次传输只有 137 B 且命中缓存;改一个小文件只传 155 B;没有上下文或想 COPY 上下文之外的文件都会 not found。
在 Docker Engine 29.8.2(BuildKit)里实测 .dockerignore:30 MiB 的 node_modules 不忽略时传输 31.47 MB,忽略后只传 509 B(285 ms 对 1625 ms);`*.log` 只管根目录、`/build` 只匹配根目录的 build、`**/` 才匹配任意深度、`!` 例外规则后者覆盖前者;忽略经常变化的文件让 COPY 层保持缓存;Dockerfile.dockerignore 取代 .dockerignore。
在 Docker Engine 29.8.2 里实测“删除文件不会减小镜像”:先 dd 20 MiB 再下一个 RUN 里 rm,镜像比 alpine 多 41.96 MB(Size 把压缩内容和解包层各算一次),而同一个 RUN 里 dd && rm 多 0.00 MB;docker save 的层 tar 里,删除那一层只有一个 0 字节的 .wh.big.bin;从 gen 阶段启动能看到文件,最终镜像看不到;多阶段构建后只多 0.01 MB。