
在Go中,init()函数内若用:=为包级变量赋值,会意外创建同名局部变量,导致包级变量保持零值(如nil),而外部访问时看似“赋值未生效”。根本原因是短变量声明语法的遮蔽行为,而非init执行时机问题。
在go中,init函数内若用:=为包级变量赋值,会意外创建同名局部变量,导致包级变量保持零值(如nil),而外部访问时看似“赋值未生效”。根本原因是短变量声明语法的遮蔽行为,而非init执行时机问题。
你遇到的问题非常典型——表面看init()执行了、变量也“被赋值了”,但外部访问仍是nil。核心原因在于这一行:
MyVariable := "something" // ❌ 错误:这是短变量声明,创建了新的局部变量!
:= 是短变量声明(short variable declaration),它会在当前作用域(这里是init函数体内)新建一个局部变量,即使恰好与包级变量同名。这个局部变量仅在init()函数内有效,函数退出即销毁;而真正的包级变量 MyVariable 自始至终未被赋值,保持其零值(对指针/接口/切片/映射等类型即为nil)。
✅ 正确写法是使用赋值操作符 =:
// PKG2 Package (修正后)
package pkg2
import (
// ...some imports...
)
var MyVariable string // 显式声明类型,避免推断错误
func init() {
MyVariable = "something" // ✅ 正确:直接为包级变量赋值
// 此时 MyVariable 已被初始化,后续所有导入该包的代码都能看到此值
}同时,请注意以下关键点:
立即学习“go语言免费学习笔记(深入)”;
-
包级变量必须显式声明类型:原代码
var MyVariable缺少类型,Go无法推断(除非有初始值),会导致编译错误。应写为var MyVariable string或var MyVariable = "default"。 -
init()执行顺序可靠:Go保证所有包的init()函数在main()执行前完成,且按依赖顺序调用。你观察到“init先执行”是正确的,问题不在时机,而在赋值本身未作用于目标变量。 -
命名一致性:Go导出标识符需首字母大写。若想从
main包访问,变量名应为MyVariable(已满足),而非Myvariable(小写v将不可导出)。
完整可运行示例:
// pkg2/pkg2.go
package pkg2
var MyVariable string
func init() {
MyVariable = "initialized in init" // 使用 = 赋值
}// main.go
package main
import (
"fmt"
"github.com/myproject/config/pkg2"
)
func main() {
if pkg2.MyVariable == "" {
fmt.Println("❌ Still empty — likely due to := in init")
} else {
fmt.Printf("✅ Success: %s\n", pkg2.MyVariable) // 输出: ✅ Success: initialized in init
}
}总结:在init()(或任何函数)中为已有包级变量赋值时,永远使用 =,禁止使用 :=。:= 只应用于声明并初始化新变量。养成检查变量是否已声明的习惯,可有效避免此类隐蔽bug。


















