# go语言面试题总结

# 1 Go语言基础

# 1.1 new和make的区别?

点击查看答案

二者都是用来申请内存的。

  • new很少用,一般用来给基本类型申请内存的。并且内存对应的值为类型零值,返回的是指向类型的指针。比如string int返回的是对应类型的指针(*string *int)
  • make只用于slice、map以及channel的初始化,返回的还是这三个引用类型本身;

# 1.2 数组与切片的区别?

点击查看答案

1、数组是具有固定长度且拥有零个或者多个相同数据类型元素的序列。 数组的长度是数组类型的一部分, 所以[3]int 和 [4]int 是两种不同的数组类型。数组需要指定大小,不指定也会根据初始化的自动推算出大小,不可改变 ; 数组是值传递;

2、 切片 切片表示一个拥有相同类型元素的可变长度的序列。 切片是一种轻量级的数据结构, 它有三个属性:指针、长度和容量。 切片不需要指定大小; 切片是地址传递;

# 1.3 解释以下命令的作用?

go env
go run 
go build 
go get
go install
go clean
go version
1
2
3
4
5
6
7
点击查看答案

以下命令的作用

  • go env: #用于查看go的环境变量
  • go run: #用于编译并运行go源码文件
  • go build: #用于编译源码文件、代码包、依赖包
  • go get: #用于动态获取远程代码包
  • go install: #用于编译go文件,并将编译结构安装到bin、pkg目录
  • go clean: #用于清理工作目录,删除编译和安装遗留的目标文件
  • go version: #用于查看go的版本信息

# 1.4 go语言中的协程?

点击查看答案
  • 协程和线程都可以实现程序的并发执行;
  • 通过channel来进行协程间的通信;
  • 只需要在函数调用前添加go关键字即可实现go的协程,创建并发任务;
  • 关键字go并非执行并发任务,而是创建一个并发任务单元;

# 1.5 go语言中的for循环?

点击查看答案

for循环支持continue和break来控制循环,但是它提供了一个更高级的break, 可以选择中断哪一个循环 for循环不支持以逗号为间隔的多个赋值语句, 必须使用平行赋值的方式来初始化多个变量

# 1.6 go语言中没有隐藏的this指针,这句话是什么意思?

点击查看答案

方法施加的对象显式传递,没有被隐藏起来 golang的面向对象表达更直观,对于面向过程只是换了一种语法形式来表达 方法施加的对象不需要非得是指针,也不用非得叫this

# 1.7 go语言中的引用类型包含哪些

点击查看答案

数组切片、字典(map)、通道(channel)、接口(interface)

# 1.8 go语言中指针运算有哪些?

点击查看答案
  • 可以通过&取指针的地址
  • 可以通过*取指针指向的数据

# 1.9 go语言的main函数

点击查看答案
  • main函数不能带参数
  • main函数不能定义返回值
  • main函数所在的包必须为main包
  • main函数中可以使用flag包来获取和解析命令行参数

# 1.10 go语言的同步锁

点击查看答案
  • (1) 当一个goroutine获得了Mutex后,其他goroutine就只能乖乖的等待,除非该goroutine释放这个Mutex
  • (2) RWMutex在读锁占用的情况下,会阻止写,但不阻止读
  • (3) RWMutex在写锁占用情况下,会阻止任何其他goroutine(无论读和写)进来,整个锁相当于由该goroutine独占

# 1.11 go语言的channel特性

点击查看答案
  • A. 给一个 nil channel 发送数据,造成永远阻塞
  • B. 从一个 nil channel 接收数据,造成永远阻塞
  • C. 给一个已经关闭的 channel 发送数据,引起 panic
  • D. 从一个已经关闭的 channel 接收数据,如果缓冲区中为空,则返回一个零值
  • E. 无缓冲的channel是同步的,而有缓冲的channel是非同步的

# 1.12 go语言触发异常的场景有哪些

点击查看答案
  • A. 空指针解析
  • B. 下标越界
  • C. 除数为0
  • D. 调用panic函数

# 1.13 说说go语言的select机制

点击查看答案
  • A. select机制用来处理异步IO问题
  • B. select机制最大的一条限制就是每个case语句里必须是一个IO操作
  • C. golang在语言级别支持select关键字

# 1.14 线程和进程的区别

点击查看答案
  • 进程:是程序在操作系统的一次执行过程
  • 线程:是进行进程的一个执行实例,是程序的最小执行单位

# 1.15 协程之间的数据竞争怎么解决

点击查看答案

协程之间的数据竞争怎么解决(channel或者锁)?

协程之间的数据竞争怎么解决

# 1.16 协程性能优化

点击查看答案

# 1.17 切片数据结构

点击查看答案
// runtime/slice.go

type slice struct {

    array unsafe.Pointer // 元素指针,指向一个数组的指针

    len   int // 当前切片的长度

    cap   int // 当前切片的容量

} 
1
2
3
4
5
6
7
8
9
10
11

# 1.18 高并发数据抢占,通道和锁怎么实现

点击查看答案

# 1.19 select case用几个?

点击查看答案

# 1.20 内存逃逸

点击查看答案
  • 1、指针逃逸 - 方法返回局部变量指针,就形成变量逃逸
  • 2、栈空间不足逃逸 - 当切片长度扩大到10000时就会逃逸,实际上当栈空间不足以存放当前对象或无法判断当前切片长时会将对象分配到堆中
  • 3、动态类型逃逸 - 编译期间很难确定其参数的具体类型,也能产生逃逸度
  • 4、闭包引用对象逃逸 - 原本属于局部变量,由于闭包的引用,不得不放到堆上,以致产生逃逸
  • 5、跨协程引用对象逃逸 - 原本属于A协程的变量,通过指针传递给B协程使用,产生逃逸

# 2 其他

# 2.1 mysql索引

点击查看答案 普通索引 唯一索引 主键索引 组合索引 全文索引

# 2.2 优化表设计

点击查看答案

1、主键,一定要设计主键。用来唯一地标识表中的某一条记录。它能保证实体的完整性,加快数据库的操作速度,这一点很重要,一定要设置主键。

2、字段命名最好避开保留字。在给字段命名的时候,要尽量避开关键字,以免出了问题而不好查找。虽然在以关键字命名的字段上加''可以不再报错,但保险起见,就不要这么设计。

3、表名长度尽可能短。表名称不要太长,如果有转数据库的需要,表名太长(超过30个字符)无疑会增加转换的工作量。

4、尽可能不使用default null。 NULL值不能进行索引,影响索引的统计信息,影响优化器的判断。复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。

5、时间戳Timestamp。 每个表的最后都加一个create_time为时间戳类型timestamp的字段,该方式对于调试阶段非常有帮助。

6、少用外键

# 2.3 TCP与UDP的区别

点击查看答案

TCP与UDP的区别

# 2.4 RPC、RMI、HTTP、REST的区别

点击查看答案
  • RPC:远程服务调用(Remote Procedure Call),加上Protocol后可以称为远程过程调用协议,可以用不同的语言实现,可以借用HTTP协议或者其他协议来实现,一般都是通过基于TCP/IP的自定义协议实现。
  • HTTP:超文本传输协议(HyperText Transfer Protocal),是应用层的一种网络传输协议,一般格式都是json或者xml,也是基于TCP/IP实现的。
  • REST:是一种架构风格,是基于HTTP协议的,可以理解称一种API的规范,比如查询都是GET请求,新增都是POST,修改是PUT,删除是DELETE等。
  • RMI:远程方法调用(Remote Method Invocation),是一种用于实现RPC的java API,仅仅应用在java程序上,依赖于JVM,因为他仅仅支持从一个JVM到另一个JVM的调用。

# 2.5 什么时候选择递归

点击查看答案

递归,在数学与计算机科学中,是指在函数的定义中使用函数自身的方法。也就是说,递归算法是一种直接或者间接调用自身函数或者方法的算法。 通俗来说,递归算法的实质是把问题分解成规模缩小的同类问题的子问题,然后递归调用方法来表示问题的解。

  • 1 优点----->实现简单, 可读性好
  • 2 缺点-----> 递归调用,占用空间大。递归太深,易发生栈溢出。可能存在重复计算。

# 2.6 如何保持mysql和redis中数据的一致性

点击查看答案

如何保持mysql和redis中数据的一致性

上次更新: 2021-1-3 21:01:42