在编程过程当中,一定会涉及到变量的声明和使用。在golang中,对变量对声明和初始化操作有两个关键子new和make。
一开始学习的时候,就记不住,也没区分出来差异是什么。后面看了他人的文章才慢慢有点理解。就把自己的理解过程梳理出来。
变量的声明
new和make主要用于变量的声明和初始化。我们这里就先拆解出来,分两部分如何声明,如何厨师阿虎。 变量的声明我们可以通过var关键字。并且使用var在声明的时候,会给变量设置默认值。比如int类型的零值是0,string类型的零值是"",引用类型的零值是nil。
例如:int,string类型。声明的变量能够直接拿来使用。
var i int
var s string
i = 10
s = 'hello world'
//能够编译得过。
例如:引用类型,不能够直接使用。使用将会报错。
package main
import (
"fmt"
)
func main() {
var i *int
*i=10
fmt.Println(*i)
}
//编译将会报错
//panic: runtime error: invalid memory address or nil pointer dereference
对于引用类型的变量,我们不光要声明它,还要为它分配内容空间,否则我们的值放在哪里去呢?这就是上面错误提示的原因。
PS:对于这个内存空间,有一个自己的辅助性的理解。var在定义的时候具体的地址空间是这样的。
所以,这样当我们要使用引用类型的时候。就会出现错误。因为根本没有指向一个实际的内存空间地址。根本没办法赋值。所以这时候var定义完变量之后就需要进行初始化动作。 这样也就引出来new和make的作用。
new
new 會自動用 zeroed value 來初始化型別,也就是字串會是""
,number 會是 0
,channel, func, map, slice 等等則會是 nil
。
另外一个重点是:new函数,返回的是一个指向该类型内存地址的指针。
func main() {
people := new(map[string]string) //返回的是一个指针类型。
p := *people //取people指针的值。
p["name"] = "Kalan" // panic: assignment to entry in nil map //提示这里是一个nil值。
}
//-------以下的例子说明new返回的是一个指针值-------
type Person struct {
Name string
Age int
}
func main() {
//效果一样。
p := &Person{} //对定义的结构题,取指针值。
p := new(Person) //返回的是一个指针值。
}
对于上面的问题我们如何解决呢?既然我们知道了没有为其分配内存,那么我们使用new分配一个吧。
func main() {
var i *int
i=new(int) //这里就会分配一个内存空间。
*i=10
fmt.Println(*i)
}
//#另外一个例子
func main() {
u:=new(user)
u.lock.Lock()
u.name = "张三"
u.lock.Unlock()
fmt.Println(u)
}
type user struct {
lock sync.Mutex
name string
age int
}
PS:辅助理解的指针图
make
make也是用于内存分配的,但是和new不同,它只用于chan、map以及切片的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了。make不会传回来一个指针值。(因为没必要)
注意,因为这三种类型是引用类型,所以必须得初始化,但是不是置为零值,这个和new是不一样的
二者异同
所以从这里可以看的很明白了,二者都是内存的分配(堆上),但是make只用于slice、map以及channel的初始化(非零值);而new用于类型的内存分配,并且内存置为零。所以在我们编写程序的时候,就可以根据自己的需要很好的选择了。
make返回的还是这三个引用类型本身;而new返回的是指向类型的指针。
func main() {
receiver := make(chan string) // 初始化 channel,但不回傳指標
person := make(map[string]string)
people := make([]string, 100) // 初始化長度為 100 的字串陣列
//之后就可以正常使用了。
}
有需要拿到引用类型的指针的场景?
ps:在我个人的理解。在函数传递参数的时候,可以理解为传递值。对于引用类型来说,本身的值。就是一直指向“目标”的指针。所以运用到的场景应该不多。
PS:辅助理解的图(不一定正确,仅辅助自己理解)
小结
其实new不常用
所以有new这个内置函数,可以给我们分配一块内存让我们使用,但是现实的编码中,它是不常用的。我们通常都是采用短语句声明以及结构体的字面量达到我们的目的,比如:
i := 0
u := user{}
这样更简洁方便,而且不会涉及到指针这种比麻烦的操作。
- make 用于chan map slice 的初始化。
- new 初始化,返回的是。一个类型的指针。
本篇主要内容参考引用于:
https://www.flysnow.org/2017/10/23/go-new-vs-make.html
https://studygolang.com/articles/18232