golang: make 与 new 的区别

时间:2024-10-14 07:20:44

golang 中有两个内置函数可以用来在堆上分配内存,分别是 mak() 和 new(),这篇文章中会简要介绍下这两个函数的区别,以及这两个函数分别在什么情况下使用。

下面先看下 golang 中对这两个内置函数的定义。

new():

  1. func new(Type) *Type
  2. 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.

make();

  1. func make(t Type, size ...IntegerType) Type
  2. 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.

从上面两个函数的定义,我们可以看到两个明显的区别。

区别一:接收的参数个数不一样

从 new() 函数的定义可以看到,它只接收一个参数 —— Type,即要为哪种类型分配内存。

而从 make() 函数的定义可以看到,它可以接收多个参数,第一个参数也是 Type,剩下的是可选的整数类型参数。

make() 函数可以为 slice 类型分配内存,当 make() 函数为 slice 类型分配内存时,可选的整型参数可以用来指定 slice 的 length 和 capacity,示例如下:

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. my_slice := make([]int, 5, 10)
  7. (my_slice)
  8. }

运行上面的程序,会得到如下输出结果:

[0 0 0 0 0]

可以看到,golang 为我们分配了一个长度为 5 的 slice。

区别二:返回类型不一样

new() 函数返回一个指向接收参数类型的指针。

make() 函数返回类型和它接收的第一个参数类型一样。

下面我们通过一个例子来验证这一点:

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. new_int := new(int)
  7. ("new_int type: %T\n", new_int)
  8. make_slice := make([]int, 5)
  9. ("make_slice: %T\n", make_slice)
  10. }

运行上面的程序,输出结果如下:

  1. new_int type: *int
  2. make_slice: []int

可以看到,new_int 的类型是一个指向int类型的指针;而 make_slice 是一个包含int类型的 slice。

区别三:应用场景不一样

make() 函数专门用来为 slice、map、chan 来分配内存并做初始化的;而 new() 更像是一个通用的内存分配工具,可以为其他类型分配内存。

上面说到 new() 更像是一个通用的内存分配工具,但是它不可以为 slice、map、chan 这种引用类型来分配内存。这是因为 new() 只是简单的分配内存,并在内存上根据类型做零值(zero value)处理。

像slice、map、chan这样的引用类型,在创建这样类型的值后,会创建一个称作 header 的值,它其实是一个数据结构,这个数据结构中,包含一个指向底层数据结构的的指针,另外根据引用类型的不同,还会包含不同的字段用来管理底层数据结构。

以 slice 类型为例,当创建一个 slice 类型的值时,会创建一个轻量级的数据结构,这个数据结构包含三个字段:pointer、length、capacity。

  • pointer 是一个指向底层数组(underly array)的指针。
  • length 代表 slice 的长度
  • capacity 代表 slice 的容量

由此可以看到为什么不能用 new() 来创建 slice、map、chan 这样的引用类型了。如果用 new() 来创建 slice,那么创建的 header 中的 pointer 做0值处理,就会被初始化为 nil,而 length 和 capacity 也会被初始化为0,这样显然是不正确的。

总结

new() 和 make() 都是 golang 中用来分配内存的函数,本文介绍了 make() 和 new() 的三个主要的区别:

  • 接收参数个数不一样:new() 只接收一个参数,而 make() 可以接收多个参数
  • 返回类型不一样:new() 返回一个指针,而 make() 返回类型和它接收的第一个参数类型一样
  • 应用场景不一样:make() 专门用来为 slice、map、chan 这样的引用类型分配内存并作初始化,而 new() 用来为其他类型分配内存。

一如既往,如果你对文章中的内容有任何疑问,或者是发现文章中有任何错误,都可以通过留言告诉我;如果你喜欢我的文章,欢迎关注我的微信公众号 Tech For Geek。