go中make和new的区别
在golang中,make和new都是用来初始化的语句
New
我们可以用下面的语法声明一个变量
func main() {
a := new(int)
fmt.Println(reflect.TypeOf(a))
}
输出
*int
可以看到,用new来声明一个T型数据类型,返回的是T*变量
我们来看一下a所占的字节大小,以及a所指向的地址的字节大小
func main() {
a := new(int)
fmt.Println(unsafe.Sizeof(a))
fmt.Println(unsafe.Sizeof(*a))
fmt.Println(a)
fmt.Println(*a)
}
输出:
8
8
0xc00000a0d8
0
可以看出,通过new初始化,go会返回一块以及初始化的内存块来,并且为其赋零值,在该例子中,我们通过输出unsafe.Size0f(*a)可以确认a所指向的地址被初始化了内存空间,并赋予了初值。
// 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
值得一提的是,在go中,make只用于声明映射、切片和信道,所以下面的语句是错误的
a := make(int32)// wrong
fmt.Println(a)
我们通过make一个切片,并用同样的逻辑来测试make返回的类型是什么,是否为变量声明内存空间,又是否会赋初值
func main() {
a := make([]int, 0)
fmt.Println(reflect.TypeOf(a))
}
输出:
[]int
可以看到,与new不同的是,make直接返回了切片类型,而不是类型的指针,继续用下面代码验证make的预分配机制
func main() {
a := make([]int64, 0)
fmt.Println(reflect.TypeOf(a))
fmt.Println(unsafe.Sizeof(a))
fmt.Println(a)
}
输出:
[]int
24
[]
我们可以看到,make同样为变量分配了内存空间,至于内存空间大小24个自己包括了什么,大家可以去分析切片的源码,这里不多赘述,因为不同的数据类型,分配的大小并不一致,比如下面的代码
func main() {
a := make([]int64, 0)
fmt.Println(reflect.TypeOf(a))
fmt.Println(unsafe.Sizeof(a))
}
输出:
chan int
8
总结
new返回T*类型,make返回T类型
make只能用于声明引用类型,比如切片 chan ,像一些基础数据类型或者自己实现的结构体只能使用new
无论new还是make,go都会申请内存空间并赋予0值,具体的内存空间大小取决与数据结构