主题
第01章 面试题精选 —— Go 入门篇
面试官最爱在简历开头问"你为什么选 Go?"——这一章的题目就是为你准备好的标准答案。
★ 基础题(必会)
Q1:为什么 Go 适合做后端服务?
参考答案:
- 性能高:Go 是编译型语言,编译为机器码直接运行,性能接近 C/C++,比 Python 快 10-100 倍
- 并发模型先进:goroutine 比线程轻量,1MB 内存可以开几千个 goroutine,能轻松支撑高并发
- 部署简单:单个二进制文件,没有依赖,特别适合容器化部署
- 标准库强:自带 HTTP 服务器、JSON、加密、模板,开箱即用
- 工程化好:go fmt 统一风格,go test 内置测试,工具链完整
💡 加分项:举一两个实际例子,比如"我了解到字节、滴滴的核心服务大量使用 Go"。
Q2:Go 和 Java 比有什么优劣?
参考答案:
| 维度 | Go | Java |
|---|---|---|
| 启动速度 | 毫秒级 | 秒级(JVM 预热) |
| 内存占用 | 小(无 JVM) | 大(JVM 自身占几百 MB) |
| 部署 | 单文件二进制 | JAR + JRE |
| 并发 | goroutine + channel(轻量) | 线程 + 锁(重量) |
| 生态 | 较年轻,云原生强 | 老牌,企业级框架多 |
| 学习曲线 | 平缓 | 陡峭(Spring 全家桶) |
| 泛型 | 1.18 才支持 | 一直有 |
结论:Go 更适合云原生、微服务、网关、CLI;Java 更适合大型企业系统、银行核心、复杂业务建模。
Q3:一个最简单的 Go 程序长什么样?说说每一行的作用。
参考答案:
go
package main // 声明本文件属于 main 包;可执行程序入口包必须叫 main
import "fmt" // 导入 fmt 标准库(格式化输入输出)
func main() { // main 函数是程序入口,无参数无返回值
fmt.Println("hi") // 调用 fmt 包的 Println 函数,自动加换行
} // 函数结束关键考点:
main包是入口包- 一个程序必须有且仅有一个
func main() - 大括号
{必须紧跟在函数行末,不能换行写(编译器会自动加分号) - Go 没有写分号的习惯,但词法层面是有分号的
Q4:go run 和 go build 有什么区别?
参考答案:
| 命令 | 行为 | 留下产物 | 场景 |
|---|---|---|---|
go run | 编译到临时目录 → 立即执行 | 不留 | 开发调试 |
go build | 编译到当前目录 → 不执行 | 留二进制 | 发布部署 |
go install | 编译 → 装到 $GOPATH/bin | 留在全局 bin | 全局命令 |
实操延伸:go run 实际上等于 go build 到一个临时目录然后执行,所以多文件项目用 go run *.go 或 go run .。
★★ 进阶题
Q5:什么是 GOROOT、GOPATH、GOPROXY?
参考答案:
- GOROOT:Go 的安装目录(标准库所在地),通常不需要手动改
- GOPATH:早期的工作空间,Go Module 出来之前所有代码都得放这里。现在主要用于存放
go install的全局命令 - GOPROXY:模块代理服务器,国内推荐设为
https://goproxy.cn,direct
bash
go env -w GOPROXY=https://goproxy.cn,direct
go env -w GOSUMDB=off # 关闭校验(仅企业内网时)
go env -w GOPRIVATE=*.example.com # 私有仓库不走代理💡 2018 年 Go 1.11 引入 Go Module 后,项目位置就不再受限于 GOPATH 了。
Q6:Go 源码到可执行文件经历了哪些阶段?
参考答案:
源代码 .go
↓ 词法分析
↓ 语法分析 → AST(抽象语法树)
↓ 类型检查
↓ SSA 中间代码
↓ 机器码生成 + 链接
↓
可执行二进制(包含运行时 runtime)关键点:
- Go 是静态链接的——所有依赖(包括 runtime、GC、调度器)都打包到一个二进制里
- 编译速度极快,因为:①依赖分析简单 ②没有头文件 ③并行编译
- 编译出来的二进制可以跨平台:
GOOS=linux GOARCH=amd64 go build就能在 Mac 上编译出 Linux 版
Q7:Go 的二进制为什么比 C 大很多?
参考答案:
一个 Hello World 的 Go 二进制文件大约 2MB,而 C 写的只有几十 KB。原因:
- Go 二进制内嵌了 runtime:包含 GC、协程调度器、反射、内存分配器
- 默认是静态链接:标准库的代码全部打包进来
- 包含了类型元信息:用于反射和 GC
优化方法:
bash
# 去掉调试信息和符号表,能减小约 30%
go build -ldflags="-s -w" hello.go
# 进一步用 upx 压缩(大约能再减小 60%)
upx --best helloQ8:Go 适合做哪些场景,不适合做哪些?
适合 ✅:
- 后端服务、API 网关、微服务
- 云原生中间件(K8s、Docker、etcd 都是 Go 写的)
- CLI 工具(kubectl、terraform、gh)
- 网络代理、消息队列
- 区块链、底层基础设施
不太适合 ❌:
- 桌面 GUI 应用(生态弱)
- 移动开发(有 gomobile 但生态少)
- 强 CPU 密集计算(不如 C/Rust)
- 富 AI/ML 应用(Python 生态完胜)
- 复杂的领域驱动设计(DDD)(Java/C# 更顺手)
★★★ 深度题
Q9:你了解 Go 的设计哲学吗?说说你的理解。
参考答案:
"Less is More"(少即是多)
- 关键字只有 25 个(vs Java 的 50+,C++ 的 80+)
- 一种问题只推荐一种解法(vs Python 的 "There should be one obvious way")
"Composition over Inheritance"(组合优于继承)
- 没有 class、没有继承,只有 struct 嵌入
- 接口隐式实现(duck typing),降低耦合
"Don't communicate by sharing memory; share memory by communicating"
- 推荐用 channel 传递数据,而不是共享变量+加锁
- 这是 CSP(Communicating Sequential Processes)模型
"Errors are values"
- 错误是普通的值(
error接口),不是异常 - 强制显式处理,不允许"忽略"
- 错误是普通的值(
工程化优先
- 强制
gofmt格式化(消灭代码风格争论) - 内置
go test、go vet、go race detector - 编译速度优先于功能丰富度
- 强制
Q10:Go 1.x 版本里有什么需要关注的里程碑?
参考答案(截至 2024):
| 版本 | 时间 | 关键特性 |
|---|---|---|
| 1.0 | 2012 | 首个稳定版,定下兼容承诺 |
| 1.5 | 2015 | 自举(Go 编译器用 Go 写) |
| 1.11 | 2018 | Go Module(颠覆性) |
| 1.13 | 2019 | error wrapping (%w、errors.Is/As) |
| 1.14 | 2020 | goroutine 异步抢占式调度 |
| 1.18 | 2022 | 泛型(10 年来最大特性) |
| 1.21 | 2023 | min/max/clear 内置函数、slog |
| 1.22 | 2024 | for-range 循环变量重新声明、net/http 路由模式 |
💡 简历提示:写"熟悉 Go 1.21+ 新特性"会比"熟悉 Go"更专业。
📌 速记口诀
"包定 main,引入用 import,函数 main 启动;编译型,gc 自动管,并发用 goroutine"
记住这一句,回答前 4 道基础题没问题。
🎯 自测练习
- 不查资料,写出 Hello World 全部代码
- 解释
func main()中的func是不是关键字 - 用一句话告诉别人 Go 的"杀手锏"是什么
- 装一遍 Go 环境,跑通 examples 里 3 个程序
- 把你电脑上的 hello 程序用
GOOS=linux go build编译出 Linux 版本试试
完成 5 项就可以放心进入第02章了 🚀