golang中new与make的区别讲解
作者:捶捶自己 发布时间:2024-05-09 14:55:15
new和make
new
// 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
对于官方是这么解释new
的:这个内置函数功能是分配内存。第一个参数是一个自定义类型,并不是一个值,返回值为一个指向新分配好的内存空间的一个指定类型指针,并且这个内存空间会被清零(也就是变为该类型的零值)。
使用new初始化
至于使用new
进行初始化,根据语言规范:The built-in function new takes a type T and returns a value of type *T. The memory [pointed to] is initialized as described in the section on initial values.
因为go中的函数不能被重载,并且这不是可变参数,所以无法传递任何初始化数据。 取而代之的是,go将使用对类型和任何成员字段适当的任何0版本进行初始化。
零值
go语言总共分为四大类型:基本数据类型、复杂数据类型、引用数据类型和接口类型。零值是指基本数据类型和指针的初始值。
数值型零值为0
、string的零值为""
、bool的零值为false
、指针的零值为nil
。
使用示例(new也可以为数组分配内存)
a := new(int)
fmt.Printf("类型为:%T, 值为:%v\n", a, a)
fmt.Printf("类型为:%T, 值为:%v\n", *a, *a)
b := new(string)
fmt.Printf("类型为:%T, 值为:%v\n", b, b)
fmt.Printf("类型为:%T, 值为:%v\n", *b, *b)
c := new(*int)
fmt.Printf("类型为:%T, 值为:%v\n", c, c)
fmt.Printf("类型为:%T, 值为:%v\n", *c, *c)
运行结果:
类型为:*int, 值为:0xc0000a6058
类型为:int, 值为:0
类型为:*string, 值为:0xc000088220
类型为:string, 值为:
类型为:**int, 值为:0xc0000ca020
类型为:*int, 值为:<nil>
new(struct)和&struct{}区别
因为struct{}
这种操作可以对类型进行初始化,并且基于上述new的理解之后就会发现&struct{}
和new(struct)
其实这两种声明方式几乎没有区别。但我们在项目中经常会使用到这两种操作,就自然会想这两者的区别(跟本人一样)。
在我调查了一些资料后,我个人觉得他们唯一的区别就在于new
只能声明一个零值的该类型的指针并返回,但是&struct{}
可以在声明的同时进行初始化操作。
func main(){
A := new(struct) // 只能返回一个struct的指针
B := &struct{Id:1,Name:"张三"} // 可以返回一个带有默认值的struct的指针
}
上述例子就很好的说明了这个问题。
小结
new
只能开辟单个空间,不能为引用类型开辟多个空间。并且new
是对类型进行内存的开辟,返回一个指向该内存空间的指针类型。如果使用new
去初始化引用数据类型,不是很合适(当然,new
一个对象还是可以的)。因此就需要用到另一个内置函数make。
make
// The make built-in function allocates and initializes an object of type // slice, map, or chan (only). Like new, the first argument is a type, not a // value. Unlike new, make's return type is the same as the type of its // argument, not a pointer to it. The specification of the result depends on // the type:
func make(t Type, size ...IntegerType) Type
对于官方是这么解释make
的:该函数功能是分配内存并且初始化一个切片(slice/map/channel)
类型的对象。相比较内置函数new
而言,make
的第一个参数也是一个自定义类型,不是一个值。但make
的返回类型是一个和他传入的自定义参数类型完全相同的类型。并不是一个指针去指向这个新开辟的内存空间。
make
也是用于内存分配的,但是和 new
不同,它只用于 chan、map
以及 slice
的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了。
简述make的初始化(slice/map/channel)
make
在对slice/map/channel
这三种类型进行初始化时,在编译初期阶段,go语言就已经将代表make
关键字的OMAKE
节点根据参数类型的不同转换成了OMAKESLICE、OMAKEMAP、OMAKECHAN
三种不同类型的节点。这些不同的节点最终会调用不同的运行时函数来初始化数据结构。
使用示例
var a []int
fmt.Println(a[0])
// 运行结果
panic: runtime error: index out of range [0] with length 0
如果不对切片进行初始化,就无法使用
var a []int
a = make([]int, 1)
fmt.Println(a[0])
map
和chan
也同理。切片需要指定长度大小,容量可以自动扩容。如果下标超出指定的长度也会出现数组越界的情况。但是map
不会发生该情况。即使初始化map
容量为0
,map
底层也会自动进行扩容。对于channel
来说初始化容量就是初始化缓冲区长度。
总结:
make
和new
共同点都是可以开辟内存空间,给变量分配内存。
不同点在于:
两者的作用类型不同,
new
给int、string、数组
分配内存,make
给slice、map、channel
分配内存。两者的返回值不同,
new
的返回值类型为一个指向新分配好的内存空间的一个指定类型指针。而make
的返回值类型为它本身。new
分配的内存空间会被清零。make
分配空间之后会被初始化。new分配的内存空间不一定会在堆上分配,当指向这个内存空间的指针变量作用域不会在作用域外被使用,或者说这个变量只使用一次就不再使用。那么
new
分配的内存空间就会在当前的函数栈中随着栈的结束而被销毁。make则会在栈上开辟一块栈帧,栈帧里面有栈的指针和栈顶指针,分别记录栈帧的空间,随着函数的执行完毕,栈里的栈帧就会自动清空。
简单的说,new
只分配内存,make
用于slice,map,和channel
的初始化,并且不返回指针。要获得一个显式的指针,使用new
进行分配,或者显式地使用一个变量的地址。
参考资料
go语言中文网
深入学习golang
来源:https://blog.csdn.net/cczj0/article/details/128636169


猜你喜欢
- javascript/js的ajax的GET请求代码如下所示:<script type="text/javascript&q
- 如果你想用Python开发Windows程序,并让其开机启动等,就必须写成windows的服务程序Windows Service
- 图片的间隙Q:我有一张大图片,把它切割后在Dreamweaver中进行拼接,可是总是有间隙,不知为什么?A:不知你是否把表格的边距、间距和边
- 关于IE9,微软逐渐提供越来越多的内容。很多人想知道IE9有多少模式和渲染引擎,今天IE项目主管Marc Silbey就此问题进行了解答。S
- 前言本文中所有的代码使用 JavaScript 编写,但你也可以用其他兼容 JSR 223 的脚本语言。这些例子可作为脚本文件也可以在交互式
- 前言时隔108天,何同学在B站发布了最新的视频,《【何同学】我用108天开了个灯…》。那么就让我们用爬虫,爬取视频的弹
- 废话少说,直接上代码<script type="text/javascript"> &
- 前言备受期待的django 2.0已经发布了,最大的一个变化就是不再支持python2.x版本了,这也为我们还在保守使用的2.x的同学们敲响
- 本文实例讲述了php字符串截取函数mb_substr用法。分享给大家供大家参考,具体如下:string mb_substr ( string
- 最近在研究pathon的命令行解析工具,argparse,它是Python标准库中推荐使用的编写命令行程序的工具。以前老是做UI程序,今天试
- 上一篇博文,我们已经顺利的从cnodejs.org请求到了数据,但是大家可以注意到我们的/src/api/index.js的第一句就是://
- 前言入门爬虫很容易,几行代码就可以,可以说是学习 Python 最简单的途径。刚开始动手写爬虫,你只需要关注最核心的部分,也就是先成功抓到数
- 复制目录: 包含多层子目录方法: 递归, 深度遍历,广度遍历深度遍历&广度遍历:思路:1.获得源目录子级目录,并设置目标目录的子级路
- 创建复合主键: 方法一:创建表之后,alter table table_name add primary key(字段1,字段2) 
- 笔者在网上找了很多关于VSCODE配置Go语言的教程,但是由于版本等种种问题,最终都已失败告终。无奈只能在官方文档上寻求帮助,现在终于可以了
- 按照惯例,年底的淘宝的确是到了“需要改版的时候”。这次新版的淘宝首页上线,乍看并没有多少夺人眼球的地方,但仔细揣摩其中的细节,还是发现了不少
- 本文环境Python 3.6.5Django 2.0.4fix(2018.5.19):最近得知Django 的model基类需要声明为abs
- 例子:Response.Cookies("letwego")("visiter")="84
- 本来是在找交通识别的程序,然后凑巧看见了证件照换底,于是学习了一下~一开始在网上找了一个很普遍写的程序,但是效果并不好,想要放弃了,然后看见
- 通过本文给大家介绍Python3控制路由器——使用requests重启极路由.py的相关知识,代码写了相应的注释,以后再写成可以方便调用的模