数据初始化 new&make

在Go语言中,专门提供了两个专门用于数据初始化的内建函数new和make

new

new 函数用于为值分配内存。但是与其他语言如Java不同的是,它并不会去初始化分配到的内存,只会清零一块内存空间。然后将这块空间的地址作为值进行返回。这个返回的结果就是指向这个新的T类型值的指针值,*T。

正是因为有这种干净的内存分配策略,使得我们可以在用内建函数new创建某个数据类型的新值之后立刻就可以拿来使用,而不用担心这个值中会遗留某些历史痕迹。

这是一个用来分配内存的内建函数,但是与C++不一样的是,它并不初始化内存,只是将其置零。也就是说,new(T)会为T类型的新项目,分配被置零的存储,并且返回它的地址,一个类型为*T的值。在Go的术语中,其返回一个指向新分配的类型为T的指针,这个指针指向的内容的值为零(zero value)。注意并不是指针为零。

go的new操作大致相当于C语言的如下操作:

T *t = (T*)malloc(sizeof(T))
memset(t, 0, sizeof(T))

make

make函数只能用于创建切片类型、字典类型和通道类型的值。并返回一个已被初始化的(非零值的)的对应类型的值。这么做的原因是与上面3个复合类型的特殊结构有关。切片类型、字典类型、通道类型都是引用类型。在它们每一个值的内部都会保持着一个对某个低层数据结构值的引用。如果不对它们的值进行初始化,那么其中的这种引用关系是不会被建立起来的,同时相关的内部值也不会正确。在这种情况下,该类型的值也就不能被使用,因为它们是不完整的,处于未就绪的状态。这就意味着,在创建这3个引用类型的值的时候,必须将内存空间分配和数据初始化这两个步骤绑定在一起。也正是为了保证这些值的可用性,切片类型、字典类型和通道类型的零值都是nil,而不是那个未被初始化的值。因此,当我们new这3个引用类型并想创建它们的时候,得到的却是一个指向空值nil的指针。

new和make的对比

从返回值上来说,new返回的是*T,是一个指针;make的返回值直接为T类型

其次对于slice,map和channel类型的变量,我们一般都用make来创建,很少用new来进行创建。

用一段代码来说明make和new的区别:

var p = new([]int)
fmt.Printf("%+v\n", *p == nil)

*p = make([]int, 0)
fmt.Printf("%+v\n", *p == nil)

// 返回值为 true,  false

从上面的代码中就可以看出,new只是对slice分配了内存并将其置为0值(slice的0值为nil),所以 *p == nil 的判断为true; 而make则是在分配内存之后,对slice进行了初始化,不再为零值(nil)而是一个len=0的slice。

参考

powered by Gitbook该文件修订时间: 2019-07-05 09:33:43

results matching ""

    No results matching ""