对象创建严格按内存分配、零值初始化、构造函数调用三步顺序执行:先分配确定大小的内存块,再将各字段设为零值(nil/0等),最后才执行用户定义的构造逻辑。

对象创建时,内存分配、零值初始化和构造函数调用是三个严格有序的关键步骤,顺序不可颠倒,且每步职责明确。
内存分配:先有“容器”,再填内容
对象创建的第一步是为类型所需空间在堆或栈上分配连续内存块。分配大小由编译期确定的类型布局决定(含字段对齐),不依赖构造函数逻辑。例如 new Person 会按 Person 结构体总字节数申请内存,此时内存中全是未定义值(栈上)或清零后内存(堆上由 Go 的 malloc 小心处理,但语义上仍属下一步)。
零值初始化:字段自动归零,不执行任何逻辑
分配完成后,运行时将整块内存按字段逐个设置为对应类型的零值:数值为 0,指针为 nil,切片/映射/通道为 nil,结构体字段递归零值。这一步无函数调用、无副作用、不可跳过——哪怕你写了带参数的构造函数,零值初始化也一定发生在它之前。
- type T struct { a *int; b []byte } 创建时,a 自动为 nil,b 自动为 nil 切片,不是空切片
- 该过程与是否使用 &T{} 或 new(T) 无关,两者都完成完整零值初始化
构造调用:真正执行用户逻辑的唯一入口
只有前两步完成后,才调用构造函数(如自定义的 NewT() 函数或复合字面量中的字段赋值)。此时对象内存已就位、字段已归零,构造函数可安全读写字段、分配子资源、校验参数。注意:Go 语言本身无语法级构造函数,所谓“构造”是约定函数,它不参与前两步,只负责“填充”和“初始化业务状态”。
- t := &T{a: new(int)} 中,&T{} 先完成零值初始化,再把 new(int) 结果赋给 a
- 若构造函数 panic,对象内存可能已分配(尤其堆上),但因未返回有效引用,通常被 GC 回收,不会泄漏
理解这三步的分离,有助于排查字段未初始化、竞态访问、或误以为构造函数能绕过零值的问题。










