Contents

Go 语言中的 new 关键字和 make 关键字的区别

Contents

Go 语言分配内存的函数包括 new 和 make。new 用来获取类型对应的指针类型,即要获取指针类型的内存分配。make 只用来分配引用类型,即为channel,map,slice分配内存。

对于值类型的变量,我们通过var 声明,系统会默认为他分配内存空间,并赋该类型的零值。如下,我们声明一个int类型变量i,输出为0。

package main

import "fmt"

func main() {
	var i int
	fmt.Println(i)
}

而如果我们声明一个指针类型的变量,系统不会为他分配内存,改变量默认就是nil。此时如果你想直接使用,那么系统会抛异常。

var j *int
fmt.Println(j)
*j = 10  //panic: runtime error: invalid memory address or nil pointer dereference

也就是说,空指针还没有内存分配,是不能使用的。那么要想使用,此时就需要new出场啦。

var j *int  
j = new(int)  
fmt.Println(j)   
fmt.Println(*j)  
*j = 10  
fmt.Println(*j)
0xc00000a0e0
0
10

声明指针类型变量后,通过new为他分配内存,有了内存空间,这个变量就可以自由的使用啦。

我们来看一下new函数

// 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

它只接受一个参数,这个参数是一个类型,分配好内存后,返回一个指向该类型内存地址的指针。同时把分配的内存置为零,也就是类型的零值。

接着,我们来看一下make函数。

// 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. For example, make([]int, 0, 10) allocates an underlying array
//	of size 10 and returns a slice of length 0 and capacity 10 that is
//	backed by this underlying array.
//	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 是分配内存并初始化,初始化并不是置为零值。
  • 与new一样,它的第一个参数也是一个类型,但是不一样的是,make返回的是传入的类型,而不是指针!
var c chan int
fmt.Printf("%#v \n",c) //(chan int)(nil)
c = make(chan int)
fmt.Printf("%#v", c) //(chan int)(0xc000062060)

声明管道类型变量c,此时c还是nil,不可用;通过make来分配内存并初始化,c就获得了内存可以使用了。