make和new的区别
文章v2版
作用对象
make 只能用于slice,chan,map 对这些对象进行初始化
new 用于 golang任意type 自定义类型和 内置数据类型
语义
make(T,args) 初始化内置数据结构(slice,chan,map)
new(T) 根据传入的类型,分配一片零值的内存空间,并返回指向这片内存空间的指针 value *T ,显示的创建了对象的一个指针,而不必使用&T对获取该对象的地址。
官方
Allocation with new
Go has two allocation primitives, the built-in functions
new
andmake
. They do different things and apply to different types, which can be confusing, but the rules are simple. Let's talk aboutnew
first. It's a built-in function that allocates memory, but unlike its namesakes in some other languages it does not initialize the memory, it only zeros it. That is,new(T)
allocates zeroed storage for a new item of typeT
and returns its address, a value of type*T
. In Go terminology, it returns a pointer to a newly allocated zero value of typeT
.
核心意思:new不会初始化内存,new(T)只是分配一个零值的存储空间,并返回指向该空间的一个地址,这个值的类型*T
,
Allocation with make
Back to allocation. The built-in function
make(T,
args)
serves a purpose different fromnew(T)
. It creates slices, maps, and channels only, and it returns an initialized (not zeroed) value of typeT
(not*T
). The reason for the distinction is that these three types represent, under the covers, references to data structures that must be initialized before use. A slice, for example, is a three-item descriptor containing a pointer to the data (inside an array), the length, and the capacity, and until those items are initialized, the slice isnil
. For slices, maps, and channels,make
initializes the internal data structure and prepares the value for use
核心意思:make(T,args)只能用于引用数据类型(slices,maps,channels),返回一个已经初始化的非零值对象T。引用数据类型使用之前必须初始。
Q&A
Golang的零值有那些?
类型 | 零值 | 描述 |
---|---|---|
Int,int16,int32,int64 | 0 | |
Uint,uint16,uint32,uint64 | 0 | |
Float32,float64 | 0 | |
Complex64,complex128 | (0+0i) | 复数 |
chan,map,slice,func,interface,ptr | nil | |
String | "" | 空串 |
bool | false |
返回一个零值指针怎么理解?
In Go terminology, it returns a pointer to a newly allocated zero value of type
T
.
大致意思:在Go术语中,new(T)
返回一个指向new
刚刚分配的类型为T的零值指针。
- 代码中p指向了 new分配的类型为map[int]string的一个零值对象的地址
package main
import (
"fmt"
"reflect"
)
func main() {
var p = new(map[int]string)
// p 的类型 *map[int]string
fmt.Println(reflect.TypeOf(p).String())
// 打印结果 true
// p 就是零值指针,而*p就 零值指针指向那个对象的值
fmt.Println(*p == nil)
}
slice,chan,map,为什么要使用make?
- 打印的结果都为true
package main
import (
"fmt"
"reflect"
)
func main() {
var sslics []int
var mmap map[int]string
var cchan chan int
// 三者都为nil
// 打印结果 true true true
fmt.Println(sslics == nil, mmap == nil, cchan == nil)
}
- 向一个为nil的
map
读写数据,将会导致panic,使用make可以指定map的初始空间大小,以容纳元素。如果未指定,则初始空间比较小。 - 向一个为nil的
chan
读写数据,会导致deadlock!
,使用make可以初始化chan
,并指定chan
是缓存chan(make(chan T,size)
),还是非缓存chan(make(chan T)
) - 向一个为nil的
slice
写数据会怎样?
package main
import "fmt"
// 数据正常添加
func main() {
var sslices []int
// append 适用于 切片类型
sslices = append(sslices, 1)
fmt.Println(sslices)
}
-
slice为什么要使用
make
呢?- 使用make可以在创建
slice
时,定义切片的len
,cap
的大小 - 使用make可以创建一个
非零值
的引用对象
- 使用make可以在创建
package main
import "fmt"
func main() {
// 分配一个 大小为10的底层数组,并返回一个 长度为0,容量为10的切片
slices := make([]int, 0, 10)
slices = append(slices, 1)
// 打印结果 [1] false
fmt.Println(slices, slices == nil)
}