Hello,大家好!我是阳哥。
最近我们团队把过往的Go面试题都整理了一下,做成了一个2026年Go最新最全面试题pdf文档,因为篇幅有限,为了方便大家阅读和学习,我打算把这份文档里的精华内容,分几期文章分享出来。
这是第一篇,我们先来聊聊 Go 语言的基础对比和一些核心概念,精选了 20 道高频面试题,希望能助你一臂之力!
在了解 Go 语言是不是面向对象(简称:OOP) 之前,我们必须先知道 OOP 是啥,得先给他 “下定义”,根据 Wikipedia 的定义,我们梳理出 OOP 的几个基本认知:
基于这几个基本认知进行一步延伸出,面向对象的三大基本特性:
特性 | Go | Java |
|---|---|---|
函数重载 | 不允许(函数/方法名必须唯一) | 允许 |
执行速度 | 编译型语言,速度通常更快 | 运行在 JVM 上,速度相对较慢 |
多态 | 默认不支持(需通过接口实现) | 默认允许 |
路由配置 | 使用 HTTP 协议进行路由配置 | 使用 Akka.routing 等工具配置 |
扩展性 | 代码可自动扩展到多个核心 | 并不总是具有足够的可扩展性 |
继承方式 | 匿名组合(支持多重组合/伪继承) | extends 关键字(不支持多继承) |
是的,也不是。原因是:
面向对象中的 “封装” 指的是可以隐藏对象的内部属性和实现细节,仅对外提供公开接口调用,这样子用户就不需要关注你内部是怎么实现的。
在 Go 语言中的属性访问权限,通过首字母大小写来控制:
面向对象中的 “继承” 指的是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
在 Go 语言中,是没有类似 extends 关键字的这种继承的方式,在语言设计上采取的是组合的方式。
面向对象中的 “多态” 指的同一个行为具有多种不同表现形式或形态的能力,具体是指一个类实例(对象)的相同方法在不同情形有不同表现形式。
在 Go 语言中,多态是通过接口来实现的。只要不同的类型实现了同一个接口,它们就可以作为该接口类型被调用,从而实现多态。
特性 | Go | Python |
|---|---|---|
范例 | 基于并发编程范式的过程编程语言 | 基于 OOP 的多范式,命令式和函数式 |
类型化 | 静态类型(编译时捕获错误) | 动态类型 |
并发 | 内置并发机制 (Goroutine/Channel) | 无内置并发机制 (需依赖库) |
安全性 | 强类型,编译型,更安全 | 强类型,解释型,运行时检查 |
内存管理 | 允许程序员一定程度管理内存 | 完全自动化,由 VM 管理 |
语法 | 基于括号 {} | 使用缩进指示代码块 |
if err != nil 语句较多。[]interface{} 不支持下标操作。共同点: 给变量分配内存
不同点对比:
特性 | new | make |
|---|---|---|
作用变量类型 | 任意类型 | 仅限 slice, map, channel |
返回类型 | 指针 (*T) | 变量本身 (T) |
内存状态 | 分配空间并清零 | 分配空间并初始化 |
for range 循环中,变量的地址会发生变化吗?这个问题的答案取决于使用的 Go 版本。
a, b)在内存中只有一份。每次迭代都会将新值覆盖写入这同一块内存,因此它们的地址在循环中始终不变。作用:defer 延迟函数,释放资源,收尾工作;如释放锁,关闭文件,关闭链接;捕获 panic。
顺序:多个 defer 调用顺序是 LIFO(后入先出),defer 后的操作可以理解为压入栈中。
执行流程:

修改返回值时机:defer 可以修改函数最终返回值,修改时机主要是在有名返回值或者函数返回指针的情况下。
超过最大存储值如 uint8 最大是 255。
var a uint8 = 255
var b uint8 = 1
// a + b = 0
总之类型溢出会出现难以意料的事,需要注意。
rune 相当 int32。
Golang 中的字符串底层实现是通过 byte 数组的,中文字符在 unicode 下占 2 个字节,在 utf-8 编码下占 3 个字节,而 golang 默认编码正好是 utf-8。
类型 | 等同于 | 常用场景 |
|---|---|---|
byte | uint8 | 处理 ASCII 字符 |
rune | int32 | 处理 Unicode 或 UTF-8 字符 |
Go 中解析的 tag 是通过反射实现的。
反射原理:反射是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。反射将接口变量转换成反射对象 Type 和 Value;反射可以通过反射对象 Value 还原成原先的接口变量;反射可以用来修改一个变量的值。
常见的库如 gorm, json, yaml, gin.Bind() 等都是通过反射来实现 tag 解析的。
Golang 都是传值。
传递方式 | 描述 | 建议场景 |
|---|---|---|
值传递 | 复制一份实参传递给函数。函数内修改不影响原数据。 | 结构体较小,且不需要修改原数据时。 |
引用传递 (指针) | 复制指针。函数内修改可能影响原数据。 | 结构体较大(避免大内存拷贝),或需要修改原数据时。 |
主要分为以下 4 种场景:
Go 的 select 为 golang 提供了多路 IO 复用机制。
Select 执行流程:

Select 的特性:
每个 defer 语句都对应一个 _defer 实例,多个实例使用指针连接起来形成一个单连表,保存在 goroutine 数据结构中。每次插入 _defer 实例,均插入到链表的头部,函数结束再一次从头部取出,从而形成后进先出的效果。
Defer 的规则总结:
符号 | 类型 | 含义 | 是否支持转义 |
|---|---|---|---|
单引号' | rune / byte | 表示字符 (int32/uint8) | 支持 |
双引号" | string | 字符串 (字符数组) | 支持 |
反引号` | string | 字符串字面量 (Raw String) | 不支持 (所见即所得) |
Go 中是不提供 Set 类型的。
我们可以利用 map 类型来实现一个 set。因为 map 的 key 是不能重复的。 Value 我们可以用一个常量来代替,比如一个空结构体 struct{}。实际上空结构体不占任何内存,使用空结构体,能够帮我们节省内存空间,提高性能。
好了,今天的分享就先到这里。
这 20 道题只是《Go 最新最全面试题》中的冰山一角。因为篇幅原因,剩下的内容我会在后面的文章中继续分享。