本文详解 go 语言中跨包访问与赋值全局变量的正确方式,重点解决因误用短变量 declaration `:=` 导致的编译错误,并提供线程安全、可维护的数据库连接初始化实践。
在 Go 中,跨包共享状态(例如 MongoDB 的全局 *mgo.Session)是常见需求,但必须严格遵循 Go 的变量作用域与声明规则。你遇到的错误:
./server.go:28: cannot declare name dbutil.MySession
根本原因在于::= 是短变量声明操作符,仅用于在同一作用域内创建并初始化新变量;它不能用于给已存在的包级变量赋值,更不允许带包名前缀(如 dbutil.MySession)进行声明。
✅ 正确做法是分两步完成:
修改 server.go 中的 main() 函数如下:
func main() {
var err error
dbutil.MySession, err = dbutil.ConnectDb() // ✅ 使用 = 赋值,不加 :=
if err != nil {
log.Fatal("Failed to connect to MongoDB:", err)
}
defer dbutil.MySession.Close() // 确保程序退出前释放资源
// 启动 HTTP 服务
http.HandleFunc("/users", getUsersHandler)
http.HandleFunc("/posts", getPostsHandler)
log.Println("Server starting on :8080")
log.Fatal(http.ListenAndServe(":8080", ni
l))
}⚠️ 重要注意事项:
示例:使用 sync.Once 安全初始化(推荐)
// 在 dbutil.go 中
var (
once sync.Once
session *mgo.Session
initErr error
)
func GetSession() (*mgo.Session, error) {
once.Do(func() {
session, initErr = ConnectDb()
})
return session, initErr
}这样既避免了 main() 中手动赋值的耦合,又保证了线程安全与按需初始化。总结:Go 不支持“带包名的短声明”,跨包赋值请始终使用 =,并优先采用显式、可控、可测试的状态管理方式。