所谓引用类型(reference type)特指 slice、map、channel 这三种预定义类型。

相比数字、数组等类型,引用类型拥有更复杂的存储结构。除分配内存外,它们还须初始化一系列属性,诸如指针、长度,甚至包括哈希分布、数据队列等。

内置函数 new 按指定类型长度分配零值内存,返回指针,并不关心类型内部构造和初始化方式。而引用类型则必须使用 make 函数创建,编译器会将 make 转换为目标类型专用的创建函数(或指令),以确保完成全部内存分配和相关属性初始化。

除 new/make 函数外,也可使用初始化表达式,编译器生成的指令基本相同。

a := make([]int, 0)
// 或
b := []int{}

new 函数也可为引用类型分配内存,但这是不完整创建。以字典(map)为例,它仅分配了字典类型本身(实际就是个指针包装)所需内存,并没有分配键值存储内存,也没有初始化散列桶等内部属性,因此它无法正常工作。

p := new(map[string]int) // 函数new返回指针 
m := *p            
m["a"] = 1 // panic: assignment to entry in nil map(运行期错误) 
fmt.Println(m)