Go语言中的make和new函数的区别及使用场景

简介: 本文详细解析了Go语言中`make`和`new`函数的使用方法及区别。`make`用于创建切片、映射和通道等引用类型,返回初始化后的值;`new`用于创建任意类型的零值对象,返回指向该对象的指针。文章通过多个示例说明两者的应用场景,并总结了面试中可能遇到的相关问题,如底层实现、使用场景及优缺点等,帮助读者更好地理解和区分这两个函数。

在Go语言中,make和new是两个常用的函数,用于创建变量或数据结构。它们的使用方法和作用有一些区别,下面将详细介绍它们的使用和区别,并给出一些可能在面试中遇到的坑。

make函数

make函数用于创建切片、映射和通道等引用类型的数据结构。它的语法如下:

scss

体验AI代码助手

代码解读

复制代码

make(T, size)

其中,T表示切片、映射或通道的类型,size表示长度或容量。

示例1:创建一个长度为5,容量为10的整型切片

go

体验AI代码助手

代码解读

复制代码

slice := make([]int, 5, 10)

示例2:创建一个长度为0,容量为5的整型切片

go

体验AI代码助手

代码解读

复制代码

slice := make([]int, 0, 5)

示例3:创建一个长度为0,容量为5的映射

go

体验AI代码助手

代码解读

复制代码

m := make(map[string]int, 5)

示例4:创建一个容量为10的整型通道

go

体验AI代码助手

代码解读

复制代码

ch := make(chan int, 10)

make函数返回的是一个初始化后的(非零值)引用类型变量,即返回的是一个指向新分配的对象的指针。

new函数

new函数用于创建指定类型的零值对象,并返回该对象的指针。它的语法如下:

scss

体验AI代码助手

代码解读

复制代码

new(T)

其中,T表示要创建的类型。

示例1:创建一个整型变量的指针

dart

体验AI代码助手

代码解读

复制代码

var num *int
num = new(int)

示例2:创建一个结构体变量的指针

go

体验AI代码助手

代码解读

复制代码

type Point struct {
    X, Y int
}
var p *Point
p = new(Point)

示例3:创建一个字符串变量的指针

csharp

体验AI代码助手

代码解读

复制代码

var str *string
str = new(string)

new函数返回的是一个指向新分配的零值对象的指针。

make和new的区别

  • make函数只能用于创建切片、映射和通道等引用类型的数据结构,而new函数可以用于创建任意类型的变量。
  • make函数返回的是一个初始化后的(非零值)引用类型变量的指针,而new函数返回的是一个指向新分配的零值对象的指针。

在面试中,可能会遇到以下坑:

  • 有些面试官会混淆make和new的使用场景,所以在回答问题时要明确区分它们的作用和使用方法。
  • 可能会出现让你解释make和new的底层实现原理的问题,这时候你可以简单地解释它们的作用和返回值即可,不需要过于深入。
  • 面试官可能会问你make和new的使用场景和优缺点,所以在准备面试时要对它们的使用方法和区别有清晰的理解。

面试题

比如说以下面试题:

  1. make和new函数的区别是什么?
  • make函数用于创建切片、映射和通道,返回的是对应类型的初始化后的值。
  • new函数用于创建指定类型的指针,并返回指针。
  1. make函数只能用于哪些数据结构的创建?
  • make函数可以用于创建切片、映射和通道。
  1. new函数只能用于哪些类型的变量的创建?
  • new函数可以用于创建任意类型的变量,返回的是指向该类型零值的指针。
  1. make函数返回的是什么类型的值?
  • make函数返回的是对应数据结构的初始化后的值,类型为切片、映射或通道。
  1. new函数返回的是什么类型的值?
  • new函数返回的是指向指定类型零值的指针。
  1. make函数在底层是如何实现的?
  • make函数在底层会分配内存并初始化对应数据结构,然后返回初始化后的值。
  1. new函数在底层是如何实现的?
  • new函数在底层会分配内存,并返回指向该类型零值的指针。
  1. make和new函数的使用场景有哪些?
  • make函数常用于创建切片、映射和通道,并进行初始化。
  • new函数常用于创建指定类型的指针,特别是用于创建结构体变量的指针。
  1. 在创建切片时,使用make函数和new函数有什么区别?
  • 使用make函数创建切片可以指定切片的长度和容量,并进行初始化。
  • 使用new函数创建切片只会返回一个指向切片类型的指针,需要手动进行切片的初始化。

go

  1. 体验AI代码助手
  2. 代码解读
  3. 复制代码
// 使用make函数创建切片
slice := make([]int, 5, 10)
fmt.Println(slice) // [0 0 0 0 0]

// 使用new函数创建切片
ptr := new([]int)
fmt.Println(ptr) // &[]
  1. 在创建映射时,使用make函数和new函数有什么区别?
  • 使用make函数创建映射可以进行初始化,并指定映射的初始容量。
  • 使用new函数创建映射只会返回一个指向映射类型的指针,需要手动进行映射的初始化。

go

  1. 体验AI代码助手
  2. 代码解读
  3. 复制代码
// 使用make函数创建映射
m := make(map[string]int)
m["a"] = 1
fmt.Println(m) // map[a:1]

// 使用new函数创建映射
ptr := new(map[string]int)
*ptr = make(map[string]int)
(*ptr)["b"] = 2
fmt.Println(*ptr) // map[b:2]
  1. 在创建通道时,使用make函数和new函数有什么区别?
  • 使用make函数创建通道可以指定通道的缓冲区大小,并进行初始化。
  • 使用new函数创建通道只会返回一个指向通道类型的指针,需要手动进行通道的初始化。

go

  1. 体验AI代码助手
  2. 代码解读
  3. 复制代码
// 使用make函数创建通道
ch := make(chan int, 5)
ch <- 1
fmt.Println(<-ch) // 1

// 使用new函数创建通道
ptr := new(chan int)
*ptr = make(chan int)
*ptr <- 2
fmt.Println(<-*ptr) // 2
  1. 在创建结构体变量时,使用make函数和new函数有什么区别?
  • 使用make函数无法创建结构体变量,只能用于创建切片、映射和通道。
  • 使用new函数可以创建结构体变量的指针。

go

  1. 体验AI代码助手
  2. 代码解读
  3. 复制代码
// 使用new函数创建结构体变量的指针
type Person struct {
    Name string
    Age  int
}

ptr := new(Person)
fmt.Println(ptr) // &{ 0}

总结

make和new是Go语言中常用的函数,用于创建变量或数据结构。make函数用于创建切片、映射和通道等引用类型的数据结构,返回的是一个初始化后的引用类型变量的指针;而new函数用于创建任意类型的变量,返回的是一个指向新分配的零值对象的指针。在面试中,要注意区分它们的使用场景和区别,并准备好相关的面试题。


转载来源:https://juejin.cn/post/7309065017190072335

相关文章
|
10天前
|
人工智能 安全 Java
Go与Java泛型原理简介
本文介绍了Go与Java泛型的实现原理。Go通过单态化为不同类型生成函数副本,提升运行效率;而Java则采用类型擦除,将泛型转为Object类型处理,保持兼容性但牺牲部分类型安全。两种机制各有优劣,适用于不同场景。
54 24
|
28天前
|
SQL JSON 前端开发
较为完整的SpringBoot项目结构
本文介绍了SpringBoot项目的分层结构与目录组成。项目分为四层:**controller层**(前端交互)、**service层**(业务逻辑处理)、**dao层**(数据库操作)和**model层**(实体类定义)。分层设计旨在实现关注点分离,降低耦合度,提高系统灵活性、可维护性和扩展性。此外,还详细说明了项目目录结构,包括`controller`、`service`、`dao`、`entity`、`param`、`util`等子目录的功能划分,便于团队协作开发。此架构有助于前后端分离,明确各模块职责,符合高内聚低耦合的设计原则。
193 1
|
2月前
|
算法 Java Python
垃圾回收机制 | Python
Python 的垃圾回收机制采用“引用计数”为主,“分代回收”和“标记-清除”为辅的策略。引用计数通过跟踪对象的引用次数,实时释放无引用对象的内存,但存在循环引用问题。分代回收将对象按存活时间分为三代,优先回收短命对象,减少性能开销。标记-清除技术用于解决容器对象的循环引用问题,通过标记不可达对象并清除它们,但需全量扫描堆内存,效率较低。这三种机制共同确保 Python 内存管理的高效与稳定。
101 30
|
7月前
|
存储 Java C#
深入理解synchronized实现原理
本文深入讲解了Java中`synchronized`关键字的实现原理。`synchronized`确保同一时刻只有一个线程能进入临界区,并保证共享变量的内存可见性。它通过monitor机制实现,作用于方法时使用ACC_SYNCHRONIZED标志,作用于代码块时使用monitorenter和monitorexit指令。每个对象都有一个与之关联的monitor,线程需获取monitor锁才能执行同步代码。Monitor内部包含_EntryList、_Owner、_WaitSet等队列,管理线程的加锁、等待和唤醒过程。
170 0
深入理解synchronized实现原理
|
7月前
|
存储 SQL 关系型数据库
mysql 的ReLog和BinLog区别
MySQL中的重做日志和二进制日志是确保数据库稳定性和可靠性的关键组件。重做日志主要用于事务的持久性和原子性,通过记录数据页的物理修改信息来恢复未提交的事务;而二进制日志记录SQL语句的逻辑变化,支持数据复制、恢复和审计。两者在写入时机、存储方式及配置参数等方面存在显著差异。
178 6
|
7月前
|
SQL 存储 缓存
MySQL执行流程
本文介绍了MySQL的执行流程,分为server层和引擎层。server层包含连接器、查询缓存、解析器、预处理器、优化器等组件,负责SQL的接收、解析、优化及执行;引擎层负责数据的存储与读取。文章详细解释了各组件的功能,如连接器负责用户身份认证,查询缓存提高查询效率,解析器进行SQL的词法和语法分析,预处理器验证表和字段的存在性,优化器选择最优执行计划,最终由查询执行引擎完成查询并将结果返回给客户端。
175 0
MySQL执行流程
|
2月前
|
Java
java 多线程异常处理
本文介绍了Java中ThreadGroup的异常处理机制,重点讲解UncaughtExceptionHandler的使用。通过示例代码展示了当线程的run()方法抛出未捕获异常时,JVM如何依次查找并调用线程的异常处理器、线程组的uncaughtException方法或默认异常处理器。文章还提供了具体代码和输出结果,帮助理解不同处理器的优先级与执行逻辑。
|
9月前
|
XML Java API
SpringBoot 整合 Minio
本文介绍了如何在服务器上安装并配置Minio服务,包括Minio的依赖、配置类以及基本操作。首先,通过Maven添加Minio依赖;接着,在`yml`文件中配置Minio的连接信息;然后,创建`MinIoClientConfig`类将MinioClient注入到Spring容器中;最后,定义`OSSFileService`接口及其实现类`OssFileServiceImpl`,实现文件上传、获取文件URL、临时访问URL和删除文件等操作。
203 2
|
4月前
|
人工智能 安全 Java
深入理解Java浅拷贝与深拷贝
本文深入探讨Java中浅拷贝与深拷贝的概念、实现方式及应用场景。浅拷贝通过`clone()`方法复制对象引用,修改新对象会影响原对象;深拷贝则创建完全独立的新对象,确保数据安全。文章通过代码示例讲解两种拷贝方式的实现,并分析其优缺点。同时,针对List类型提供浅拷贝和深拷贝的具体实现方法,帮助读者更好地理解和应用这两种技术。选择拷贝方式时需权衡对象复杂度、大小及操作安全性等因素。
203 2
|
5月前
|
SQL 网络协议 关系型数据库
MySQL 主从复制
主从复制是 MySQL 实现数据冗余和高可用性的关键技术。主库通过 binlog 记录操作,从库异步获取并回放这些日志,确保数据一致性。搭建主从复制需满足:多个数据库实例、主库开启 binlog、不同 server_id、创建复制用户、从库恢复主库数据、配置复制信息并开启复制线程。通过 `change master to` 和 `start slave` 命令启动复制,使用 `show slave status` 检查同步状态。常见问题包括 IO 和 SQL 线程故障,可通过重置和重新配置解决。延时原因涉及主库写入延迟、DUMP 线程性能及从库 SQL 线程串行执行等,需优化配置或启用并行处理
179 40