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
newandmake. They do different things and apply to different types, which can be confusing, but the rules are simple. Let's talk aboutnewfirst. 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 typeTand 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,makeinitializes 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)
}