feat: add 10 Golang interview questions

Added comprehensive Golang interview preparation materials:
- 基础语法(值类型、切片、map、defer、接口、struct、new/make)
- Goroutine 和并发模型(与线程对比、调度模型、内存模型)
- 错误处理和测试(error、panic/recover、单元测试、Benchmark)
- 并发编程进阶(Mutex、RWMutex、WaitGroup、atomic、数据竞争)
- HTTP 和 Web 开发(Client、Server、中间件模式)
- 内存模型和垃圾回收(内存分配、逃逸分析、GC)
- 性能优化(pprof、内存优化、CPU优化、并发优化)
- 反射和 unsafe(反射性能、unsafe 使用场景)
- 接口和类型系统(类型断言、interface{}、类型嵌入、泛型)
- 数据库操作(database/sql、GORM、事务、SQL 注入防护)
- 项目结构和工程化(标准项目结构、Go Module、CI/CD)

Each file includes:
- Detailed questions and comprehensive answers
- Code examples and best practices
- Alibaba P7 level requirements

Total: 60 interview questions (50 backend + 10 Golang)

Generated with [Claude Code](https://claude.com/claude-code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
yasinshaw
2026-03-01 00:16:36 +08:00
parent 0e46a367c4
commit ab3a99f131
10 changed files with 2854 additions and 0 deletions

View File

@@ -0,0 +1,408 @@
# Golang 错误处理和测试
## 问题
1. Go 的错误处理机制是什么?为什么不用 try-catch
2. panic 和 recover 的使用场景是什么?
3. errors.Wrap 和 errors.Is 的作用是什么?
4. Go 的单元测试如何写?有哪些最佳实践?
5. table-driven test 是什么?
6. Go 的基准测试Benchmark如何写
---
## 标准答案
### 1. Go 的错误处理
#### **error 接口**
```go
type error interface {
Error() string
}
```
**特点**
- 错误是值,不是异常
- 必须显式处理
- 避免嵌套过深
---
#### **创建错误**
```go
import "errors"
// 1. 简单错误
err1 := errors.New("something went wrong")
// 2. fmt.Errorf
err2 := fmt.Errorf("invalid user: %s", "alice")
// 3. 错误包装Go 1.13+
if err != nil {
return fmt.Errorf("query failed: %w", err)
}
```
---
#### **处理错误**
```go
func readFile(path string) ([]byte, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("read file failed: %w", err)
}
return data, nil
}
```
---
### 2. panic 和 recover
#### **panic**
**用途**:不可恢复的错误(程序无法继续运行)
```go
// panic 示例
func doPanic() {
panic("something terrible happened")
}
func main() {
doPanic()
fmt.Println("this will not print")
}
```
---
#### **recover**
**用途**:捕获 panic防止程序崩溃
```go
func safeExecute() {
defer func() {
if err := recover(); err != nil {
fmt.Println("recovered from:", err)
}
}()
panic("oh no!")
}
func main() {
safeExecute()
fmt.Println("program continues")
}
```
---
#### **最佳实践**
1. **避免使用 panic**:除非是真正不可恢复的错误
2. **recover 只在 defer 中使用**:其他地方无效
3. **库代码不应 panic**:应该返回 error
---
### 3. 错误包装和判断
#### **errors.Wrap**
```go
import (
"errors"
"fmt"
)
func queryDB() error {
return errors.New("connection failed")
}
func service() error {
err := queryDB()
if err != nil {
return fmt.Errorf("service failed: %w", err) // 包装错误
}
return nil
}
func main() {
err := service()
if err != nil {
// 检查错误链
if errors.Is(err, errors.New("connection failed")) {
fmt.Println("is connection error")
}
// 获取最底层的错误
var connErr error = errors.New("connection failed")
if errors.Is(err, connErr) {
fmt.Println("connection error occurred")
}
}
}
```
---
#### **自定义错误类型**
```go
import "errors"
type ValidationError struct {
Field string
Message string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("%s: %s", e.Field, e.Message)
}
func validate(name string) error {
if name == "" {
return &ValidationError{Field: "name", Message: "required"}
}
return nil
}
func main() {
err := validate("")
var ve *ValidationError
if errors.As(err, &ve) {
fmt.Println("validation error:", ve.Field, ve.Message)
}
}
```
---
### 4. 单元测试
#### **基本测试**
```go
package mypackage
import "testing"
func Add(a, b int) int {
return a + b
}
func TestAdd(t *testing.T) {
result := Add(1, 2)
if result != 3 {
t.Errorf("Add(1, 2) = %d; want 3", result)
}
}
```
---
#### **Table-Driven Test表格驱动测试**
```go
func TestAddTableDriven(t *testing.T) {
tests := []struct {
a, b int
want int
}{
{1, 2, 3},
{2, 3, 5},
{10, -5, 5},
}
for _, tt := range tests {
t.Run(fmt.Sprintf("%d+%d", tt.a, tt.b), func(t *testing.T) {
if got := Add(tt.a, tt.b); got != tt.want {
t.Errorf("Add(%d, %d) = %d; want %d", tt.a, tt.b, got, tt.want)
}
})
}
}
```
---
#### **子测试Subtests**
```go
func TestAll(t *testing.T) {
t.Run("Test1", func(t *testing.T) {
// Test1
})
t.Run("Test2", func(t *testing.T) {
// Test2
})
}
```
---
### 5. 基准测试Benchmark
#### **基本 Benchmark**
```go
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
Add(1, 2)
}
}
```
**运行**
```bash
go test -bench=. -benchmem
```
---
#### **Benchmark 高级用法**
```go
func BenchmarkAddParallel(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
Add(1, 2)
}
})
}
func BenchmarkLargeSlice(b *testing.B) {
b.ResetTimer() // 重置计时器
data := make([]int, 1000000)
b.StartTimer()
for i := 0; i < b.N; i++ {
_ = len(data)
}
}
```
---
### 6. Mock 和测试替身
#### **使用接口进行 Mock**
```go
type Database interface {
Query(id int) (string, error)
}
type Service struct {
db Database
}
func (s *Service) GetUser(id int) (string, error) {
return s.db.Query(id)
}
// Mock 实现
type MockDatabase struct {
MockQuery func(id int) (string, error)
}
func (m *MockDatabase) Query(id int) (string, error) {
return m.MockQuery(id)
}
// 测试
func TestService_GetUser(t *testing.T) {
mockDB := &MockDatabase{
MockQuery: func(id int) (string, error) {
return "Alice", nil
},
}
service := &Service{db: mockDB}
name, err := service.GetUser(1)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if name != "Alice" {
t.Errorf("got %s; want Alice", name)
}
}
```
---
### 7. 测试最佳实践
#### **1. 测试覆盖率**
```bash
# 查看覆盖率
go test -cover
# 生成覆盖率报告
go test -coverprofile=coverage.out
go tool cover -html=coverage.out
```
---
#### **2. 测试隔离**
```go
// 每个测试独立
func Test1(t *testing.T) {
// setup
// test
// teardown
}
func Test2(t *testing.T) {
// 不依赖 Test1
}
```
---
#### **3. 使用 TestMain**
```go
func TestMain(m *testing.M) {
// 全局 setup
fmt.Println("setup before all tests")
m.Run()
// 全局 teardown
fmt.Println("teardown after all tests")
}
```
---
### 8. 阿里 P7 加分项
**深度理解**
- 理解 Go 错误处理的设计哲学(显式优于隐式)
- 理解 panic/recover 的实现机制
- 理解 table-driven test 的优势
**实战经验**
- 有编写高质量单元测试的经验(覆盖率 > 80%
- 有使用 Mock 进行测试的经验
- 有编写 Benchmark 进行性能优化的经验
**测试策略**
- 理解如何设计可测试的代码(依赖注入、接口)
- 理解如何进行集成测试和端到端测试
- 理解如何设计测试用例(边界条件、异常情况)