sync.once是go中实现线程安全单例唯一推荐方式,因其通过原子操作与轻量锁确保初始化函数仅执行一次、内存可见且阻塞等待;而if+mutex存在竞态、重排、死锁及性能问题。

sync.Once 是 Go 里实现线程安全单例最可靠的方式,不是靠 if instance == nil 加锁就能搞定的。
为什么不用 mutex + nil 判断?
常见错误是写成:if instance == nil { mu.Lock(); defer mu.Unlock(); if instance == nil { instance = &T{} } }。这看似双重检查,但缺少内存屏障,编译器或 CPU 可能重排指令,导致其他 goroutine 看到未完全初始化的 instance。Go 的 sync.Once 内部用 atomic.LoadUint32 和 atomic.StoreUint32 保证执行顺序和可见性。
Factory 模式别硬套 interface{}
Go 里工厂函数返回具体类型或接口更自然,而不是返回 interface{} 再强转。强转丢失类型安全,也绕过编译器检查。
- ✅ 推荐:
func NewPayment(method string) Payment,其中Payment是明确接口 - ❌ 避免:
func NewPayment(method string) interface{},调用方要写p := NewPayment("alipay").(*Alipay) - 场景差异:配置驱动的支付网关适合前者;插件系统若需动态加载,才考虑
plugin包,而非靠interface{}模糊类型
Active Object 模式不是“加 goroutine 就完事”
把方法调用丢进 go f() 不等于实现了 Active Object。真正的 Active Object 必须有任务队列、调度逻辑和结果同步机制。
- 核心组件缺一不可:一个接收请求的
chan、一个或多个消费者 goroutine、可选的响应chan或sync.WaitGroup - 容易踩坑:不设缓冲区的
chan在高并发下直接阻塞调用方,违背“异步”本意;没做背压控制,goroutine 泛滥 - 性能影响:如果任务本身极轻量(比如只是更新一个计数器),引入 channel 和 goroutine 反而增加开销,不如直接同步调用
Decorator 模式在 HTTP 中最常被误用
很多人用嵌套结构体模拟装饰器,但 Go 更惯用的是函数式中间件 —— 把 http.Handler 当参数传,返回新 http.Handler。
- ✅ 正确姿势:
func WithAuth(next http.Handler) http.Handler,组合时写WithAuth(WithLogging(handler)) - ❌ 错误姿势:定义
type AuthDecorator struct { next Handler },再实现ServerHTTP方法 —— 多余且难测试 - 关键区别:函数式装饰器天然支持任意组合顺序;结构体方式一旦嵌套深了,就难以拆解或替换某一层
Object Pool 在连接池场景有价值,但在短生命周期对象上反而拖慢 GC;Builder 对字段多、可选参数复杂的结构体有用,对只有两三个字段的类型纯属增加认知负担。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











