go中用 指针 共享配置 对象 ,即多个组件持有同一配置地址,实现修改一处、全局生效;需启动时初始化指针,避免函数内重赋值,推荐依赖注入而非 全局变量 ,并注意 并发 安全与原地更新。

用 Go 指针共享配置对象,核心是让多个组件持有同一份配置的地址,而非各自拷贝一份值。这样修改一处,所有引用它的地方立即生效,适合运行时动态更新或全局统一管理的场景。
配置 结构体 + 指针传递
定义一个配置结构体,初始化后取其地址传给其他函数或结构体字段。Go 中结构体默认按 值传递,必须显式用 & 取地址才能共享。
- 避免在函数内 new 或重新赋值指针变量(如
cfg = &Config{……}),否则会切断原有引用 - 推荐在启动时一次性初始化配置指针,后续只读或安全写入
- 示例:
全局配置指针(谨慎使用)
可声明包级变量保存配置指针,方便跨文件访问,但要注意并发安全和初始化顺序。
- 用
var GlobalConfig *Config声明,配合init()或显式LoadConfig()初始化 - 多 goroutine 同时读写时,需加
sync.RWMutex保护写操作 - 不建议直接导出指针变量(如
var Config *Config),应 封装 为函数(func GetConfig() *Config)控制访问
依赖注入替代全局变量
更推荐把配置指针作为参数注入到服务对象中,提高可测试性和解耦度。
- 构造函数 接收
*Config,存为结构体字段 - 测试时可传入 mock 配置,无需修改全局状态
- 例如:
type APIServer struct {cfg *Config}<br> func NewAPIServer(cfg *Config) *APIServer {<br> return &APIServer{cfg: cfg}<br>}
运行时更新配置的安全做法
若需热更新配置,不要直接替换整个指针(GlobalConfig = newCfg),而应原地更新字段,并加锁保证可见性。
- 更新单个字段:
cfg.Port = 9090—— 安全,前提是无竞态 - 批量更新:用互斥锁包裹写操作,或使用
atomic.Value存储指针(适合完全替换配置实例) - 避免“先 new 新结构体,再赋值给指针”这种看似简洁实则易错的操作
基本上就这些。指针共享配置不复杂但容易忽略生命周期和并发问题,关键是始终明确谁拥有配置内存、谁负责初始化、谁允许修改。