Effective Go

new

用来分配内存的内建函数, 不会初始化内存, 只会将内存置零. new(T) 会为类型为 T 的新项分配已置零的内存空间, 并返回它的地址, 也就是一个类型为 *T 的值. 用 Go 的术语来说, 它返回一个指针, 该指针指向新分配的, 类型为 T 的零值.

既然 new 返回的内存已置零, 那么当你设计数据结构时, 每种类型的零值就不必进一步初始化了, 这意味着该数据结构的使用者只需用 new 创建一个新的对象就能正常工作. 例如, bytes.Buffer 的文档中提到 “零值的 Buffer 就是已准备就绪的缓冲区. “ 同样, sync.Mutex 并没有显式的构造函数或 Init 方法, 而是零值的 sync.Mutex 就已经被定义为已解锁的互斥锁了.

make

内建函数 make(T, args) 的目的不同于 new(T). 它只用于创建切片(slice)、映射(map)和信道(channel), 并返回类型为 T(而非 *T)的一个已初始化(而非置零)的值. 出现这种用法差异的原因在于, 这三种类型本质上为引用数据类型, 它们在使用前必须初始化. 例如, 切片是一个具有三项内容的描述符, 包含一个指向(数组内部)数据的指针、长度以及容量, 在这三项被初始化之前, 该切片为 nil. 对于切片、映射和信道, make 用于初始化其内部的数据结构并准备好将要使用的值. 例如,

make([]int, 10, 100)

会分配一个具有 100 个 int 的数组空间, 接着创建一个长度为 10, 容量为 100, 并指向该数组中前 10 个元素的切片结构. (生成切片时, 其容量可以省略) 与此相反, new([]int) 会返回一个指向新分配的, 已置零的切片结构, 即一个指向 nil 切片值的指针.

make 只适用于映射、切片和信道且不返回指针. 若要获得明确的指针, 请使用 new 分配内存.