T 代表某个具体类型,例如 int 或 User。*T 叫作“指向 T 的指针”,它保存的不是 T 的内容本身,而是这个变量所在的地址。
new(T) → 准备一个值为零值的 T → 返回它的地址,类型是 *T
零值是一个类型在没有显式赋值时的默认值:整数是 0,布尔值是 false,字符串是空字符串,结构体的每个字段也各自取零值。
type User struct {
Name string
Active bool
}
p := new (User )
fmt.Printf ("%T %#v\n" , p, *p)
// *main.User main.User{Name:"", Active:false}
new(User) 的结果是 *User,所以变量 p 保存地址。*p 是解引用,也就是沿着地址取出真正的 User 值。
Go 1.26+:new 也能接收表达式
表达式是能够计算出一个值的代码,例如 18、user.Name 或函数调用 yearsSince(born)。从 Go 1.26 起,new(x) 会先计算 x,再创建同类型变量,把 x 的值放进去,最后返回指针。
zero := new (int ) // *int,指向 0;所有 Go 版本都支持
age := new (18 ) // *int,指向 18;需要 Go 1.26+
name := new ("Ada" ) // *string,指向 "Ada";需要 Go 1.26+
Go 1.26+:new(x) → 计算表达式 x → 创建同类型变量并写入 x → 返回该变量的指针
无类型常量会先转成默认类型,例如 new(18) 得到 *int。new(nil) 不合法,因为单独的 nil 没有可确定的具体类型。
p := new(User) 的两步结果
变量 p 类型:*User 保存内容:右侧变量的地址
指向
一个新的 User 变量
Name ""
Active false
左边拿到地址,右边保存真正的数据;右边所有字段先采用各自的零值。
最应记住:new(User) 返回的是地址 *User,不是 User 值;被指向的 User 已经完成零值初始化。
new 不是构造函数
构造函数通常会检查参数、设置业务默认值或维护约束。new(T) 只采用 T 的零值,new(x) 只采用表达式 x 算出的值;它们都不会自动调用名为 NewUser 的函数,也不会理解“新用户默认应该启用”这样的业务规则。
func NewUser (name string ) *User {
return &User {Name: name, Active: true }
}
避免误解: new(User) 是语言内置的零值分配;NewUser(...) 只是项目自己命名的普通函数,两者没有自动联系。