golang 中有两个内置函数可以用来在堆上分配内存,分别是 mak() 和 new(),这篇文章中会简要介绍下这两个函数的区别,以及这两个函数分别在什么情况下使用。
下面先看下 golang 中对这两个内置函数的定义。
new():
-
func new(Type) *Type
-
-
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();
-
func make(t Type, size ...IntegerType) Type
-
-
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,示例如下:
-
package main
-
-
import (
-
"fmt"
-
)
-
-
func main() {
-
my_slice := make([]int, 5, 10)
-
(my_slice)
-
}
运行上面的程序,会得到如下输出结果:
[0 0 0 0 0]
可以看到,golang 为我们分配了一个长度为 5 的 slice。
区别二:返回类型不一样
new() 函数返回一个指向接收参数类型的指针。
make() 函数返回类型和它接收的第一个参数类型一样。
下面我们通过一个例子来验证这一点:
-
package main
-
-
import (
-
"fmt"
-
)
-
-
func main() {
-
new_int := new(int)
-
("new_int type: %T\n", new_int)
-
-
make_slice := make([]int, 5)
-
("make_slice: %T\n", make_slice)
-
}
运行上面的程序,输出结果如下:
-
new_int type: *int
-
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。