Go 的 new 和 make 区别
date
Nov 21, 2022
slug
new-and-make
status
Published
tags
Go
summary
type
Post
简介
先上结论
new(T)
返回T类型的指针,指向T类型的零值make(T)
返回初始化后的T的引用,只能用于slice、map、channel
在Go里面,你几乎很少会遇到必须使用new的场景
make
make用来初始化
slice、map、channel
,并返回这些结构的引用如果我们使用
var
来声明一个结构体,将会是nil值,对nil值操作可能会引起panic,只有赋值之后才能使用,下面我们看看这个测试用例输出结果:
可以看到确实是符合我们上面的分析
new
new(T)
适用的T范围更广,它返回T类型的指针,指向T类型的零值比如说这个例子:
输出:
我们可以通过这个例子看到
var
和new
的区别,var
一个指针此时是nil的,未经赋值直接使用会panic,而new
就不会有这种问题出现实际上我们很少会用到
new
因为它总是可以被其它操作替代输出结果:
你可以看到上面四种Car都是指针,它们输出结果都是一致的,其中
&Car
是最简洁的声明方式了C/C++语言的选手可能会感到疑惑,为什么不用
(&Car3).id
也能拿到id
的值呢?这是因为Go从语言层面做了优化:
如果x是指针,&x里面属性集合包含了m,那么x.m和(&x).m是等价的,Go会自动转换
扩展
既然提到了指针,我们来聊聊指针相关的东西吧
指针比较原则
Go定义了指针比较原则:
- 只有同类型的指针才能比较
如果你在1.18之前尝试对不同类型的指针比较,就会报错,提示你:
- 指针指向同一个对象,或者都是nil的时候比较结果是
true
- 否则比较结果都是
false
比如这个例子
传引用?还是传值?
先说结论:Go是值传递,所有类型数据都会拷贝一个副本到函数里面。
但是Go又把数据类型分为两种:
- 引用类型:指针、slice、map、channel、接口、函数等
- 非引用类型:int、string、float、bool、数组和struct
引用类型传递的时候依然会拷贝一个副本,但是这个副本和引用指向了同一个对象,因此函数内的修改会影响原引用数据
而非引用类型就是普通的值传递了,不会影响到原有的数据
输出结果: