make 和 new 的区别
当我们在 Go 中想初始化一个结构时,可能会考虑两个关键词 make 和 new . make 和 new
是内建的两个函数,主要用来创建分配类型内存。
make
在 builtin.go 中对 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 是一个内置函数,用来初始化一个 slice 或 map 或 chan 类型的对象。第一个需要的参数是一个类型 type ,然后可以有第二个或第三个参数,这需要根据类型来确定。对于 slice 来说,第二个、第三个参数分别是长度和容量,但是如果长度和容量相等时可以缺省一个,看起来就只有两个参数。对于 map 和 chan 类型来说,第二个参数是容量,没有第三个参数。
和 new 不同的是, make 的返回值的类型和输入的类型是一样的,也就是说返回值不是一个指针,而是一个对象。
然后需要注意的是,对于 slice 来说,容量不能小于长度。 make([]int, 0, 10) 会分配一个 size 为10的底层数组,然后返回一个 slice ,这个 slice 由该底层数组支持,长度为0,容量为10.
对于 map ,会分配一个足够的空间来容纳指定数量的元素,但这个 map 目前是空的。当省略了大小的时候,会分配一个小的初始大小。
对于 chan ,会用指定的容量,来初始化通道的缓冲区。如果省略了容量,那么得到的通道就是无缓冲的。
需要注意的是, make 的只能用来初始化内置的数据结构,也就是slice、map和 channel,此时编译器不一定不知道你需要使用多少内存,这些数据结构占用的内存是运行时才能知晓的。slice、map、channel 这些类型它是复合类型数据结构,通常是一个结构体+堆内存,因此 make 的额外作用就是初始化这些数据和指针,从这一点看,make 的作用是申请内存,并且初始化数据。
new
在 built.go 中对 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
也就是说, new 是 Go 中的一个内置函数,用来分配内存的。传给它一个 类型 Type ,它就会根据该类型分配一块内存,该内存里存储的是该类型的零值,然后返回一个该类型的指针,指向这块内存。
使用 new 时,编译器知道你需要使用多少内存(通过计算该类型的大小), new 可以用于任何一种类型。
例如:
t := new(T)
等同于
var temp T
t := &temp
通常情况下,我们很少用 new .
如果用到,通常是用来 new 一个结构体,如
type S struct {
a int
b float64
}
s := new(S)
我们在编写 Mit6.824 实验的代码中,在 MakeClerk 时就是通过 new 来获得一个 clerk 结构体类型的指针的。
此外,当我们声明一个指针类型时,一定要new一个,这是为了给这个指针分配内存,不然会报内存地址为空,如
var i *[]int
i = new([]int)
fmt.Println(i) // &[]
fmt.Println(len(i)) // 0
此时打印 i 的话,会得到 &[] , 打印 len(*i) 会得到 0
实在不懂可以记住一句话:make 只能用于 map 、slice 、channel ,new 只能用于结构体
回答
make:make能够分配并初始化类型所需的内存空间和结构,返回引用类型的本身;make具有使用范围的局限性,仅支持 channel、map、slice三种类型;make 函数会对三种类型的内部数据结构(长度、容量等)赋值。
new:new能够分配类型所需的内存空间,返回指针引用(指向内存的指针);new可被替代,能够通过字面值快速初始化。