Go 的 build tag 与条件编译:跨平台代码隔离的最佳实践

在 Go 里做跨平台系统编程,靠 `runtime.GOOS` 写运行期分支并不能解决编译期符号冲突。本文以文件锁封装为例,梳理 build tag、文件命名规则、Unix 与 Windows 差异,以及实现时最容易踩到的类型和语义问题。 跨平台 Go 代码一旦碰到系统调用,真正难点往往不是运行时分支,而是怎样避免编译期就被平台符号拖垮。

Go 的 build tag 与条件编译:跨平台代码隔离的最佳实践

写了多年 Go Benchmark,为什么你应该用 `b.Loop()`?

Go 1.24 新增的 `testing.B.Loop()`,把基准测试里最常见的两类问题一起收拾了:一类是结果未使用时被编译器优化掉,另一类是初始化和清理阶段需要手动控制计时。对长期维护 Benchmark 的 Go 开发者来说,它不只是写法变短,更直接影响测试结果是否可信。

写了多年 Go Benchmark,为什么你应该用 `b.Loop()`?

别让路径穿越毁了服务:Go 中的 os.Root 实践

路径穿越一直是文件上传、下载和静态资源处理里的高风险问题。Go 1.24 新增的 os.Root 把目录边界控制下沉到系统调用层,能同时应对 ../ 逃逸、符号链接绕过和 TOCTOU 风险。本文结合原理与示例,梳理它在实际服务中的用法和适用边界。

别让路径穿越毁了服务:Go 中的 os.Root 实践

Go 语言中 time.After、Timer 和 Ticker 怎么选?

Go 里的超时与定时逻辑看似简单,真正容易出问题的往往是循环分配、Timer 重置语义和 Ticker 退出方式。本文按 Go 1.23 前后差异拆解 time.After、Timer、Ticker 与 AfterFunc 的适用边界,帮助你按场景选型并避开常见误用。 超时控制、延迟执行、定时轮询在 Go 服务中几乎无处不在,但真正容易出问题的,往往不是 API 会不会用,而是生命周期、版本语义和并发边。

Go 语言中 time.After、Timer 和 Ticker 怎么选?

Go context.AfterFunc:取消时如何安全清理资源

Go 服务里很多资源泄漏,不是忘了写 Close,而是取消路径没有收好。本文围绕 context.AfterFunc 的触发方式、stop 的真实语义、幂等清理和可等待封装四个问题展开,说明它适合解决什么场景,以及哪些边界必须自己补齐。

Go context.AfterFunc:取消时如何安全清理资源

从 io.Reader 到 io.WriterTo:Go I/O 抽象为什么这么耐用

Go 的 I/O 接口看起来极简,真正耐用的地方却不在“简单”,而在稳定的最小抽象加上按需增强。本文从 `io.Reader`、`io.Copy` 到 `io.WriterTo` 的调用路径出发,拆开 Go 标准库如何在不改业务签名的前提下,同时兼顾复用、可测试性和性能优化。

从 io.Reader 到 io.WriterTo:Go I/O 抽象为什么这么耐用

net/http 超时如何配置?避免慢连接拖垮服务

Go 的 net/http 启动简单,但默认写法并不会替生产环境兜住慢连接风险。本文按连接生命周期拆解服务端与客户端的超时配置,说明 ReadHeaderTimeout、ReadTimeout、WriteTimeout、IdleTimeout 和 context 分别该管什么、哪些场景容易误配,以及一组适合公网服务起步的配置思路。

net/http 超时如何配置?避免慢连接拖垮服务

Go 切片截取后,为什么大数组迟迟无法释放?

Go 中把大切片截成小切片后,内存迟迟不降,通常不是 GC 不工作,而是小切片还在引用原来的大数组。本文从切片结构、GC 可达性、复制方案、三索引切片的边界和排查思路几方面说明,帮助你判断什么时候该直接截取,什么时候必须主动复制。

Go 切片截取后,为什么大数组迟迟无法释放?