// The new built-in function allocates memory. The first argument is a type, // not a value, and the value returned is a pointer to a newly // allocated zero value of that type. func new(Type) *Type从上面的代码可以看出,new 函数只接受一个参数,这个参数是一个类型,并且返回一个指向该类型内存地址的指针。同时 new 函数会把分配的内存置为零,也就是类型的零值。
var sum *int sum = new(int) //分配空间 *sum = 98 fmt.Println(*sum)当然,new 函数不仅仅能够为系统默认的数据类型,分配空间,自定义类型也可以使用 new 函数来分配空间,如下所示:
type Student struct { name string age int } var s *Student s = new(Student) //分配空间 s.name ="dequan" fmt.Println(s)这里如果我们不使用 new 函数为自定义类型分配空间(将第 7 行注释),就会报错:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x80bd277]
goroutine 1 [running]:
// The make built-in function allocates and initializes an object of type // slice, map, or chan (only). Like new, the first argument is a type, not a // value. Unlike new, make's return type is the same as the type of its // argument, not a pointer to it. The specification of the result depends on // the type: // Slice: The size specifies the length. The capacity of the slice is // equal to its length. A second integer argument may be provided to // specify a different capacity; it must be no smaller than the // length, so make([]int, 0, 10) allocates a slice of length 0 and // capacity 10. // Map: An empty map is allocated with enough space to hold the // specified number of elements. The size may be omitted, in which case // a small starting size is allocated. // Channel: The channel's buffer is initialized with the specified // buffer capacity. If zero, or the size is omitted, the channel is // unbuffered. func make(t Type, size ...IntegerType) Type通过上面的代码可以看出 make 函数的 t 参数必须是 chan(通道)、map(字典)、slice(切片)中的一个,并且返回值也是类型本身。
注意:make 函数只用于 map,slice 和 channel,并且不返回指针。如果想要获得一个显式的指针,可以使用 new 函数进行分配,或者显式地使用一个变量的地址。
Go语言中的 new 和 make 主要区别如下:
func callnew(t *types.Type) *Node { if t.NotInHeap() { yyerror("%v is go:notinheap; heap allocation disallowed", t) } dowidth(t) if t.Size() == 0 { z := newname(Runtimepkg.Lookup("zerobase")) z.SetClass(PEXTERN) z.Type = t return typecheck(nod(OADDR, z, nil), ctxExpr) } fn := syslook("newobject") fn = substArgTypes(fn, t) v := mkcall1(fn, types.NewPtr(t), nil, typename(t)) v.SetNonNil(true) return v }需要提到的是,哪怕当前变量是使用 var 进行初始化,在这一阶段也可能会被转换成 newobject 的函数调用并在堆上申请内存:
func walkstmt(n *Node) *Node { switch n.Op { case ODCL: v := n.Left if v.Class() == PAUTOHEAP { if prealloc[v] == nil { prealloc[v] = callnew(v.Type) } nn := nod(OAS, v.Name.Param.Heapaddr, prealloc[v]) nn.SetColas(true) nn = typecheck(nn, ctxStmt) return walkstmt(nn) } case ONEW: if n.Esc == EscNone { r := temp(n.Type.Elem()) r = nod(OAS, r, nil) r = typecheck(r, ctxStmt) init.Append(r) r = nod(OADDR, r.Left, nil) r = typecheck(r, ctxExpr) n = r } else { n = callnew(n.Type.Elem()) } } }当然这也不是绝对的,如果当前声明的变量或者参数不需要在当前作用域外生存,那么其实就不会被初始化在堆上,而是会初始化在当前函数的栈中并随着函数调用的结束而被销毁。
func newobject(typ *_type) unsafe.Pointer {
return mallocgc(typ.size, typ, true)
}
本文链接:http://task.lmcjl.com/news/15160.html