Go语言单例模式如何实现_Go语言单例模式教程【通俗】
sync.Once是最安全的单例初始化方式,天然解决并发首次调用竞态问题,只执行一次闭包;须作包级或结构体字段,避免局部变量失效;panic后会持续失败,需自行兜底。Go 里 sync.Once 是最安全的单例初始化方式直接用 sync.Once 做初始化保护,比手写锁或检查更可靠。它天然解决多协程并发首次调用时的竞态问题,且只执行一次闭包,不会重复初始化。常见错误是自己用 if instance == nil + sync.Mutex 判断,但没加 double-check(即锁内再判一次),导致可能初始化多次或 panic。sync.Once 不关心你初始化的是什么类型,只保证闭包只跑一次;适合全局配置、DB 连接池、日志实例等不要把 sync.Once 放在函数局部变量里——它必须是包级或结构体字段,否则每次调用都新建一个,失去意义如果初始化函数可能 panic,sync.Once 会记住这次失败,后续调用仍会 panic;需自行兜底(比如用返回值+重试逻辑)用 init() 函数实现“编译期单例”要谨慎init() 确实只运行一次,但它发生在包加载时,无法按需延迟初始化,也不支持传参或错误处理。一旦出错,整个程序启动失败,排查困难。典型误用场景:在 init() 里连数据库、读配置文件、启动 HTTP server——这些操作都可能失败或耗时,不该塞进 init()。立即学习“go语言免费学习笔记(深入)”;init() 适合无副作用、确定成功的小型初始化,比如注册 encoder、预设常量映射表若依赖外部资源(如文件、网络),务必改用 sync.Once + 显式 GetXXX() 函数多个 init() 函数执行顺序由导入路径决定,不可控;别指望靠它做依赖排序带参数的单例不能靠全局变量硬编码需要传参(比如 DB 地址、超时时间)的单例,不能直接定义全局变量然后在 init() 或包初始化时赋值。那样会导致参数固化、无法测试、难以复用。 WisPaper 复旦大学研发的AI学术搜索工具,5分钟内筛选1000篇论文
