Go 能同时提供 HTTP 和 WebSocket 服务吗?可以,而且实现很直接
Go 完全可以在同一个服务实例里同时提供 HTTP 接口和 WebSocket 服务。关键在于 WebSocket 先通过 HTTP 握手,再由服务端按路由升级连接。借助 `net/http` 和 `gorilla/websocket`,几十行代码就能跑通,并且仍适合进一步扩展到生产场景。
Go 完全可以在同一个服务实例里同时提供 HTTP 接口和 WebSocket 服务。关键在于 WebSocket 先通过 HTTP 握手,再由服务端按路由升级连接。借助 `net/http` 和 `gorilla/websocket`,几十行代码就能跑通,并且仍适合进一步扩展到生产场景。

Go 项目里写 Makefile,核心不是把命令堆进去,而是把构建、测试、质量检查和工具依赖整理成团队可复用的入口。本文从基础模板、进阶写法到模块化拆分,梳理一份更适合实际项目落地的写法思路。

Go 里“结构体值”和“结构体指针”最容易混淆的,不是能不能调用方法,而是调用后到底改没改原对象、方法集是否一致、性能成本落在哪。本文用值接收器与指针接收器的实际例子拆开讲,并给出日常开发中更稳妥的选择规则。

在 Go 里,一个 goroutine 不能像操作系统线程那样被另一个 goroutine 直接“杀死”。这不是能力缺失,而是并发模型刻意保持的安全边界。理解这一点后,再看 context、channel 和 runtime.Goexit 的适用范围,才能写出退出路径清晰、资源释放可控的并发代码。

在 Go 里判断字符串是否为空,常见写法是 `len(s) == 0` 和 `s == ""`。两者在运行时性能基本没有差别,关键区别在于语义表达:前者强调长度,后者强调值。真正的选择标准,不是“哪个更快”,而是当前代码想表达什么。

`//go:` 开头的注释并不是普通备注,而是 Go 编译器识别的编译指示。它们能影响逃逸分析、内联、条件编译、资源嵌入甚至链接行为。本文按使用场景梳理常见指令,说明各自作用、典型写法与风险边界,帮助你在读源码或做底层优化时判断哪些能用、哪些最好别碰。

Go 的 map 在删除大量元素后,通常不会像很多人预期的那样直接把底层容量缩小。真正发生的是对溢出桶的整理:满足条件时触发一次不改 B 值的重排,改善查找效率,却未必明显降低内存占用。理解这点,才能正确判断何时需要手动重建 map。

Go 并发写日志到文件时,真正要分清的是“会不会写乱字符”和“要不要保证行顺序”这两件事。底层机制通常能保证单次写入内容完整,但并不能自动保证多 goroutine 的日志顺序。文章结合源码、系统行为和实际场景,梳理什么时候不用加锁、什么时候必须串行化。

Go 程序里最常见的路径坑,不在代码能不能读文件,而在相对路径默认跟着“启动工作目录”走。本文把问题来源、4 种常见解法和适用场景拆开说明,帮助你判断什么时候靠启动规范就够,什么时候该改成代码兜底或环境变量方案。

Go 1.18 引入 `any` 后,很多开发者开始把它视为 `interface{}` 的新写法。两者在表示空接口时确实完全等价,但它们的适用边界并不相同:`any` 适合表达“任意类型”,并不能拿来声明带方法的接口契约。 Go 1.18 引入 `any` 之后,不少 Go 开发者开始把它当成 `interface{}` 的“新版写法”。

Go 以静态编译著称,但这不代表它完全没有运行时扩展能力。本文结合官方 plugin 包的基础示例、接口化设计方式和使用边界,梳理 Go 插件机制到底能做什么、适合什么场景,以及上线前最该注意的兼容性问题。

在 Go 并发场景里,`sync.Map` 和 `Mutex+map` 都能解决共享数据安全问题,但它们擅长的负载完全不同。本文结合 Go 1.24 之后 `sync.Map` 的实现变化、典型代码写法和常见业务场景,帮助你判断何时该图省事,何时该选可控性更强的锁加普通 `map`。
