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类型的零值
比如说这个例子:
输出:
我们可以通过这个例子看到varnew 的区别,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
引用类型传递的时候依然会拷贝一个副本,但是这个副本和引用指向了同一个对象,因此函数内的修改会影响原引用数据
而非引用类型就是普通的值传递了,不会影响到原有的数据
输出结果:
 

Ref


© hhmy 2019 - 2024