这两个函数都用于分配内存,但两者之间仍然有一些差异。本文介绍它们之间的差异,以及各自的应用场景。简言之,new分配内存但不初始化内存;make分配内容并初始化内存,所谓初始化即给变量赋初始值。举例,字符串为空,整型为0,布尔变量为false。
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
new函数参数是类型,返回值是指针,指向该类型的内存地址,分配的内存被设为零值,即该类型的零值,就是说字符串为空,整型为0,布尔变量为false等。
下面请看示例:
package main
import (
"fmt"
)
func main() {
type P struct {
Name string
Age int
}
var a *[2]int
var s *string
var b *bool
var i *int
var ps *P
a = new([2]int)
s = new(string)
b = new(bool)
i = new(int)
ps = new(P) //structure
fmt.Println(a, " ", *a)
fmt.Println(s, " ", *s)
fmt.Println(b, " ", *b)
fmt.Println(i, " ", *i)
fmt.Println(ps, " ", *ps)
}
输出结果:
&[0 0] [0 0]
0xc00004c250
0xc00001a098 false
0xc00001a0c0 0
&{ 0} { 0}
上面是基本类型,下面看slice、map、Chan,new操作的结果进行对比:
package main
import (
"fmt"
)
func main() {
//map operation
var mp *map[string]string
mp = new(map[string]string)
//*mp = make(map[string]string)
// if previous line is omitted, it will pan "Pan: assignment to entry in nil map"
(*mp)["name"] = "lc"
fmt.Println((*mp)["name"])
//slice operation
var ms *[]string
ms = new([]string)
//*ms = make([]string, 5)
// if previous line is deleted, it will "panic: runtime error: index out of range"
(*ms)[0] = "lc"
fmt.Println((*ms)[0])
}
我们看到slice,map,channel以及其他的引用类型初始化时为nil,nil不能被直接赋值。new也不能分配内存,还需要make分配内存。
make
首先查看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函数返回值与参数类型一致,而不是指针,因为make仅初始化slice,map,channel等的内存,而这些类型是引用类型,不需要返回指针。请看示例:
package main
import (
"fmt"
)
func main() {
mm := make(map[string]string)
mm["name"] = "lc"
fmt.Println(mm["name"])
mss := make([]int, 2)
mss[0] = 100
fmt.Println(mss[0])
ch := make(chan int, 1)
ch <- 100
fmt.Println(<-ch)
}
总结
make仅用于分配并初始化slice,map,channel类型,而new能分配任何数据类型。new返回指针(Type, *Type),make返回引用(Type).另外new仅分配空间,make分配的空间之后被清空并初始化。
这里顺便说下指针与引用的区别:
-
指针
指针是保存另一个变量的内存地址的变量。指针需要用*操作符解引用,以访问它所指向的内存位置。 -
引用
引用变量是别名,即已经存在的变量的另一个名称。引用和指针一样,也是通过存储对象的地址来实现的。引用可以被认为是一个具有自动间接功能的常量指针(不要与指向常量值的指针混淆!),也就是说,编译器会为你应用*操作符。