Go语言中的内建函数new和make是两个用于内存分配的原语(allocation primitives)。简单来说,new只分配内存,make用于slice,map,和channel的初始化。 内置函数new按指定类型长度分配零值内存,返回指针,并不关心类型内部构造和初始化方式。 内置函数make对引用类型进行创建,编译器会将make转换为目标类型专用的创建函数,以确保完成全部内存分配和相关属性初始化。 注意的点: 1、new(T) 返回的是 T 的指针 new(T) 为一个 T 类型新值分配空间并将此空间初始化为 T 的零值,返回的是新值的地址,也就是 T 类型的指针 *T,该指针指向 T 的新分配的零值。 2、make 只能用于 slice,map,channel make 只能用于 slice,map,channel 三种类型,make(T, args) 返回的是初始化之后的 T 类型的值,这个新值并不是 T 类型的零值,也不是指针 *T,是经过初始化之后的 T 的引用。 slice切片操作 var s1 []int
if s1 == nil {
fmt.Printf('s1 is nil --> %#v \n ', s1) // []int(nil)
}
s2 := make([]int, 3)
if s2 == nil {
fmt.Printf('s2 is nil --> %#v \n ', s2)
} else {
fmt.Printf('s2 is not nill --> %#v \n ', s2)// []int{0, 0, 0}
} slice 的零值是 nil,使用 make 之后 slice 是一个初始化的 slice,即 slice 的长度、容量、底层指向的 array 都被 make 完成初始化,此时 slice 内容被类型 int 的零值填充,形式是 [0 0 0],map 和 channel 也是类似的。 3、make(T, args) 返回的是 T 的 引用 如果不特殊声明,go 的函数默认都是按值穿参,即通过函数传递的参数是值的副本,在函数内部对值修改不影响值的本身,但是 make(T, args) 返回的值通过函数传递参数之后可以直接修改,即 map,slice,channel 通过函数穿参之后在函数内部修改将影响函数外部的值。 这说明 make(T, args) 返回的是引用类型,在函数内部可以直接更改原始值,对 map 和 channel 也是如此。 4、很少需要使用 new (1)、struct 初始化的过程,可以说明不使用 new 一样可以完成 struct 的初始化工作。
foo1 和 foo2 是同样的类型,都是 Foo 类型的值,foo1 是通过 var 声明,Foo 的 filed 自动初始化为每个类型的零值,foo2 是通过字面量的完成初始化。foo3,foo4 和 foo5 是一样的类型,都是 Foo 的指针 *Foo。 但是所有 foo 都可以直接使用 Foo 的 filed,读取或修改,为什么? 如果 x 是可寻址的,&x 的 filed 集合包含 m,x.m 和 (&x).m 是等同的,go 自动做转换,也就是 foo1.age 和 foo3.age 调用是等价的,go 在下面自动做了转换。 因而可以直接使用 struct literal 的方式创建对象,能达到和 new 创建是一样的情况而不需要使用 new。 (2)、new与map的纠纷,new为引用类型分配内存,但这是不完整创建。 map 是引用类型的:内存用 make 方法来分配。 var map1 = make(map[keytype]valuetype)。
map1 := make(map[keytype]valuetype)。 相当于:mapCreated := map[string]float32{}。 注意:如果你错误的使用 new() 分配了一个引用对象,你会获得一个空引用的指针,相当于声明了一个未初始化的变量并且取了它的地址: mapCreated := new(map[string]float32) 接下来当我们调用:mapCreated['key1'] = 4.5 的时候,编译器会报运行时错误。 转载网址:http:///2017/07/26/go-make-and-new/ |
|