Go语言中函数new与make的使用和区别
简介
Go语言中有两个生成函数new与make,容易混淆。故总结一下使用和区别。
Go语言中new和make是内建的两个函数,主要用来创建分配类型内存。
问题的引出:变量声明
var i int
var s string
变量的声明我们可以通过var关键字,然后就可以在程序中使用。
当我们不指定变量的默认值时,这些变量的默认值是他们的零值,比如:int类型的零值是0,string类型的零值是"",引用类型(数组、切片、指针等)的零值是nil。
对于例子中的两种类型的声明,我们可以直接使用,对其进行赋值输出。但是如果我们换成引用类型呢?
package main
import (
"fmt"
)
func main() {
var i *int
*i=10
fmt.Println(*i)
}
运行的时候会painc,如下:
panic: runtime error: invalid memory address or nil pointer dereference./ *无效的内存地址或无指针取消引用
可以看出,对于引用类型的变量,我们不光要声明它,还要为它分配内容空间。(Golang里引用类型定义即为“内存区域”)。
要分配内存,就引出来今天的new和make。
new
new 可以用来初始化泛型,並且返回内存地址。所以通常我們会用指针变量来接 new 后的type。
特別要注意的是,new 会自动用 zeroed value 来初始化type,也就是字串会是"",number 会是 0,channel, func, map, slice 等等则会是 nil。
因为这个特性,如果我们对 map 做以下的操作的話,会出现 panic: assignment to entry in nil map
:
func main() {
people := new(map[string]string)
p := *people
p["name"] = "Kalan" // panic: assignment to entry in nil map
}
因为初始化的map会是nil map,不像其他的primitive type一样有预设值。
如果用struct做初始化,也可以直接用&代表指向的位址,下面两个写法效果是一样的:
type Person struct {
Name string
Age int
}
func main() {
p := &Person{}
p := new(Person)
}
好处是上面的Person也可以根据自己想要传入的值额外再做设定,但new则是全部的field都会直接塞zeroed value
。
make
make
与new
不同,是用来初始化一些特别的型别,像是channel,map,slice等等。另外特别要注意的是make并不会回传指针,如果要拿到指针,就要考虑用像是new的方式来初始化型别。
func main() {
receiver := make(chan string) // 初始化 channel,但不回傳指標
person := make(map[string]string)
people := make([]string, 100) // 初始化長度為 100 的字串陣列
}
总结
二者都是内存的分配(堆上),但是make只用于slice、map以及channel的初始化(非零值);而new用于类型的内存分配,并且内存置为零。所以在我们编写程序的时候,就可以根据自己的需要很好的选择了。
make返回的还是这三个引用类型本身,更常用;而new返回的是指向类型的指针,实际工作中不太常用。