Add Chapter 4: Functions and Interfaces - Closures, Defer, Panic/Recover, and Interfaces (Deep Dive)

This commit is contained in:
openclaw
2026-03-23 23:30:20 +00:00
parent 67e47dd5dd
commit aa46d006a8
3 changed files with 1327 additions and 0 deletions

View File

@@ -0,0 +1,895 @@
# 第四章:函数与接口 —— 代码复用与多态
> **本章目标**:深入理解 Go 的函数式编程特性闭包、匿名函数、defer 机制、错误处理、panic/recover以及接口的底层实现原理和最佳实践。
## 4.1 函数基础回顾与深度解析
### 4.1.1 函数声明与调用
```go
package main
import "fmt"
// 基本函数
func add(a int, b int) int {
return a + b
}
// 省略参数类型(连续同类型)
func addShort(a, b int) int {
return a + b
}
// 多个返回值
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("除数不能为零")
}
return a / b, nil
}
// 命名返回值
func divideNamed(a, b float64) (result float64, err error) {
if b == 0 {
err = fmt.Errorf("除数不能为零")
return // 返回命名返回值
}
result = a / b
return // 返回命名返回值
}
func main() {
fmt.Println(add(3, 4))
fmt.Println(addShort(3, 4))
result, err := divide(10, 2)
if err != nil {
fmt.Println("错误:", err)
} else {
fmt.Printf("10 / 2 = %.2f\n", result)
}
result2, _ := divideNamed(20, 4)
fmt.Printf("20 / 4 = %.2f\n", result2)
}
```
**深度解析**
- **命名返回值**:适合返回值较多或需要明确语义的场景
- **省略类型**:仅适用于连续的同类型参数
- **多返回值**Go 的特色,常用于返回结果 + 错误
### 4.1.2 可变参数
```go
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
func printArgs(prefix string, args ...interface{}) {
fmt.Printf("%s: ", prefix)
for _, arg := range args {
fmt.Printf("%v ", arg)
}
fmt.Println()
}
func main() {
fmt.Println(sum(1, 2, 3, 4, 5)) // 15
fmt.Println(sum()) // 0
// 切片展开
nums := []int{10, 20, 30}
fmt.Println(sum(nums...)) // 60
printArgs("参数", 1, "hello", 3.14, true)
}
```
**深度解析**
- `...T` 表示可变参数,在函数内部被视为**切片**
- 调用时可以用 `...` 展开切片
- 可变参数必须是**最后一个参数**
---
## 4.2 匿名函数与闭包
### 4.2.1 匿名函数
```go
func anonymousFunc() {
// 定义匿名函数
func() {
fmt.Println("这是一个匿名函数")
}() // 立即调用
// 赋值给变量
multiply := func(a, b int) int {
return a * b
}
fmt.Println(multiply(3, 4)) // 12
// 作为参数传递
apply := func(f func(int, int) int, x, y int) int {
return f(x, y)
}
fmt.Println(apply(add, 5, 6)) // 11
}
```
### 4.2.2 闭包Closure⭐ 核心重点
闭包是**引用了外部变量的匿名函数**。闭包不仅包含函数本身,还包含其**创建时的环境**。
```go
func closureExample() {
// 创建计数器
counter := func() func() int {
count := 0
return func() int {
count++
return count
}
}
c1 := counter()
c2 := counter()
fmt.Println(c1()) // 1
fmt.Println(c1()) // 2
fmt.Println(c1()) // 3
fmt.Println(c2()) // 1独立的 count
fmt.Println(c1()) // 4
}
```
**深度解析**
- 闭包**捕获变量**而非值:内部函数引用的是外部变量的**引用**
- 每次调用 `counter()` 都会创建**新的 `count` 变量**
- 闭包的生命周期**长于**外部函数
### 4.2.3 闭包的陷阱
#### 陷阱 1循环中的闭包
```go
func closureLoopBug() {
funcs := make([]func(), 3)
for i := 0; i < 3; i++ {
funcs[i] = func() {
fmt.Println(i) // 捕获的是 i 的引用
}
}
for _, f := range funcs {
f() // 输出3 3 3循环结束后的 i 值)
}
}
// 正确做法
func closureLoopFix() {
funcs := make([]func(), 3)
for i := 0; i < 3; i++ {
i := i // 创建新的变量
funcs[i] = func() {
fmt.Println(i)
}
}
for _, f := range funcs {
f() // 输出0 1 2
}
}
// 或者使用参数
func closureLoopFix2() {
funcs := make([]func(), 3)
for i := 0; i < 3; i++ {
funcs[i] = func(n int) {
fmt.Println(n)
}(i)
}
for _, f := range funcs {
f() // 输出0 1 2
}
}
```
#### 陷阱 2闭包内存泄漏
```go
func closureMemoryLeak() {
largeData := make([]byte, 1024*1024) // 1MB
smallFunc := func() {
fmt.Println(len(largeData))
}
// 即使 largeData 不再需要,只要 smallFunc 存在largeData 就不会被回收
_ = smallFunc
}
```
**最佳实践**
- 如果闭包不需要引用大对象,避免捕获
- 使用 `func(n int)` 参数传递值而非捕获引用
### 4.2.4 闭包的实战应用
#### 1. 工厂函数
```go
func createMultiplier(factor int) func(int) int {
return func(x int) int {
return x * factor
}
}
func main() {
double := createMultiplier(2)
triple := createMultiplier(3)
fmt.Println(double(5)) // 10
fmt.Println(triple(5)) // 15
}
```
#### 2. 中间件模式
```go
type Handler func(string) string
func loggingMiddleware(next Handler) Handler {
return func(input string) string {
fmt.Printf("处理:%s\n", input)
result := next(input)
fmt.Printf("结果:%s\n", result)
return result
}
}
func process(input string) string {
return "处理完成:" + input
}
func main() {
handler := loggingMiddleware(process)
handler("测试数据")
}
```
---
## 4.3 defer 机制
### 4.3.1 基本用法
```go
func deferExample() {
fmt.Println("开始")
defer fmt.Println("延迟 1")
defer fmt.Println("延迟 2")
fmt.Println("结束")
}
// 输出:
// 开始
// 结束
// 延迟 2
// 延迟 1
```
**深度解析**
- `defer` 语句**立即执行**,但函数调用**延迟到外层函数返回前**
- 多个 `defer` 按**后进先出LIFO** 顺序执行
- 常用于资源清理(文件关闭、锁释放、数据库连接)
### 4.3.2 defer 参数求值时机
```go
func deferArgs() {
i := 0
defer fmt.Println("i =", i) // i 在 defer 时求值
i = 10
// 输出i = 0
}
func deferArgs2() {
i := 0
defer func() {
fmt.Println("i =", i) // i 在函数执行时求值
}()
i = 10
// 输出i = 10
}
```
**深度解析**
- 普通函数调用的参数在 `defer` 时**立即求值**
- 闭包的变量在闭包**执行时求值**
### 4.3.3 defer 的返回值修改
```go
func deferReturn() (result int) {
defer func() {
result += 10 // 修改命名返回值
}()
result = 5
return // 返回 15
}
func deferReturn2() int {
defer func() {
// 无法修改返回值(无名)
}()
return 5
}
```
### 4.3.4 常见陷阱
#### 陷阱 1在循环中使用 defer
```go
func deferLoopBug() {
for i := 0; i < 10; i++ {
f, _ := os.Open("file.txt")
defer f.Close() // 所有 defer 在函数结束时执行
// 文件描述符可能耗尽
}
}
// 正确做法
func deferLoopFix() {
for i := 0; i < 10; i++ {
func() {
f, _ := os.Open("file.txt")
defer f.Close()
// 使用 f
}() // 立即返回defer 执行
}
}
```
#### 陷阱 2defer 掩盖错误
```go
func deferError() (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("panic: %v", r)
}
}()
panic("出错了")
return nil
}
```
---
## 4.4 panic 与 recover
### 4.4.1 panic 基础
```go
func panicExample() {
defer func() {
if r := recover(); r != nil {
fmt.Println("捕获 panic:", r)
}
}()
fmt.Println("开始")
panic("发生错误")
fmt.Println("不会执行")
}
```
**深度解析**
- `panic` 立即停止当前函数,开始**栈展开**
- `recover` 必须在 `defer` 中调用才能捕获 panic
- panic 会**终止程序**,除非被 recover 捕获
### 4.4.2 使用场景
#### 1. 不可恢复的错误
```go
func divide(a, b int) int {
if b == 0 {
panic("除数不能为零") // 编程错误,应该避免
}
return a / b
}
// 正确做法:返回错误
func divideSafe(a, b int) (int, error) {
if b == 0 {
return 0, fmt.Errorf("除数不能为零")
}
return a / b, nil
}
```
#### 2. 初始化失败
```go
var config *Config
func init() {
c, err := loadConfig()
if err != nil {
panic(fmt.Sprintf("加载配置失败:%v", err))
}
config = c
}
```
### 4.4.3 自定义 panic 类型
```go
type MyError struct {
Code int
Message string
}
func (e MyError) Error() string {
return fmt.Sprintf("错误码 %d: %s", e.Code, e.Message)
}
func safeDivide(a, b int) (int, error) {
if b == 0 {
panic(MyError{Code: 1001, Message: "除数不能为零"})
}
return a / b, nil
}
func handlePanic() {
defer func() {
if r := recover(); r != nil {
if err, ok := r.(MyError); ok {
fmt.Printf("自定义错误:%v\n", err)
} else {
fmt.Printf("未知 panic: %v\n", r)
}
}
}()
safeDivide(10, 0)
}
```
---
## 4.5 接口Interfaces
### 4.5.1 接口定义与实现
```go
type Speaker interface {
Speak() string
}
type Dog struct {
Name string
}
func (d Dog) Speak() string {
return d.Name + " 汪汪叫"
}
type Cat struct {
Name string
}
func (c Cat) Speak() string {
return c.Name + " 喵喵叫"
}
func makeSound(s Speaker) {
fmt.Println(s.Speak())
}
func main() {
dog := Dog{Name: "旺财"}
cat := Cat{Name: "咪咪"}
makeSound(dog) // 旺财 汪汪叫
makeSound(cat) // 咪咪 喵喵叫
}
```
**深度解析**
- 接口是**隐式实现**:不需要 `implements` 关键字
- 只要类型实现了接口的所有方法,就**自动实现**该接口
- 接口变量可以存储**任何实现该接口的类型**
### 4.5.2 空接口
```go
func printAny(v interface{}) {
fmt.Println(v)
}
// Go 1.18+ 可以使用 anyinterface{}的别名)
func printAny2(v any) {
fmt.Println(v)
}
func main() {
printAny(1)
printAny("hello")
printAny(3.14)
printAny([]int{1, 2, 3})
}
```
### 4.5.3 类型断言
```go
func typeAssertion() {
var v interface{} = "hello"
// 基本断言
s := v.(string)
fmt.Println(s)
// 安全断言
if n, ok := v.(int); ok {
fmt.Println(n)
} else {
fmt.Println("不是 int 类型")
}
// 类型开关
switch t := v.(type) {
case int:
fmt.Printf("整数:%d\n", t)
case string:
fmt.Printf("字符串:%s\n", t)
case float64:
fmt.Printf("浮点数:%.2f\n", t)
default:
fmt.Printf("未知类型:%T\n", t)
}
}
```
### 4.5.4 接口的底层实现
**深度解析**
Go 的接口在底层由两个字段组成:
- `data`:指向实际数据的指针
- `type`:类型的描述信息(`_type`
```go
// 接口底层结构(伪代码)
type iface struct {
tab *itab // 接口表:包含类型和方法
data unsafe.Pointer
}
type itab struct {
inter *interfacetype // 接口类型
_type *_type // 具体类型
hash uint32 // 类型哈希
fun [1]unsafe.Pointer // 方法表
}
```
**空接口**`interface{}`
- 所有类型都实现空接口
- 底层是 `eface` 结构
```go
type eface struct {
_type *_type
data unsafe.Pointer
}
```
### 4.5.5 接口最佳实践
#### 1. 小接口优于大接口
```go
// 错误:接口太大
type BigInterface interface {
Read() []byte
Write([]byte) (int, error)
Close() error
Seek(int64, int) (int64, error)
// ... 很多方法
}
// 正确:拆分为小接口
type Reader interface {
Read() []byte
}
type Writer interface {
Write([]byte) (int, error)
}
type Closer interface {
Close() error
}
// 组合接口
type ReadWriter interface {
Reader
Writer
}
```
#### 2. 接口定义在使用者一侧
```go
// 错误:在定义者一侧定义接口
type Dog struct{}
func (d Dog) Speak() string { return "汪汪" }
// 在别处定义接口
type Speaker interface {
Speak() string
}
// 正确:在使用者一侧定义
func process(s Speaker) {
fmt.Println(s.Speak())
}
// Dog 自动实现 Speaker
```
#### 3. 避免过度抽象
```go
// 错误:不必要的接口
type Logger interface {
Log(string)
}
type FileLogger struct{}
func (f FileLogger) Log(msg string) {
fmt.Println("File:", msg)
}
func useLogger(l Logger) {
l.Log("test")
}
// 正确:直接使用具体类型(如果不需要多态)
func useLogger2(l FileLogger) {
l.Log("test")
}
```
---
## 4.6 深度实践:综合案例
### 4.6.1 插件系统
```go
type Plugin interface {
Name() string
Run() error
}
type HelloPlugin struct{}
func (h HelloPlugin) Name() string {
return "HelloPlugin"
}
func (h HelloPlugin) Run() error {
fmt.Println("Hello from plugin!")
return nil
}
type MathPlugin struct{}
func (m MathPlugin) Name() string {
return "MathPlugin"
}
func (m MathPlugin) Run() error {
fmt.Printf("2 + 2 = %d\n", 2+2)
return nil
}
func loadPlugins() []Plugin {
return []Plugin{
HelloPlugin{},
MathPlugin{},
}
}
func main() {
plugins := loadPlugins()
for _, p := range plugins {
fmt.Printf("加载插件:%s\n", p.Name())
if err := p.Run(); err != nil {
fmt.Println("插件运行失败:", err)
}
}
}
```
### 4.6.2 中间件链
```go
type Middleware func(Handler) Handler
type Handler func(string) string
func logging(next Handler) Handler {
return func(input string) string {
fmt.Printf("[LOG] 输入:%s\n", input)
result := next(input)
fmt.Printf("[LOG] 输出:%s\n", result)
return result
}
}
func timing(next Handler) Handler {
return func(input string) string {
start := time.Now()
result := next(input)
fmt.Printf("[TIME] 耗时:%v\n", time.Since(start))
return result
}
}
func auth(next Handler) Handler {
return func(input string) string {
if input == "" {
return "错误:空输入"
}
return next(input)
}
}
func businessLogic(input string) string {
return "处理结果:" + input
}
func main() {
// 构建中间件链
handler := auth(timing(logging(businessLogic)))
result := handler("测试数据")
fmt.Println("最终结果:", result)
}
```
### 4.6.3 错误处理链
```go
type AppError struct {
Code int
Message string
Cause error
}
func (e *AppError) Error() string {
if e.Cause != nil {
return fmt.Sprintf("错误码 %d: %s (原因:%v)", e.Code, e.Message, e.Cause)
}
return fmt.Sprintf("错误码 %d: %s", e.Code, e.Message)
}
func wrapError(err error, code int, message string) error {
if err == nil {
return nil
}
return &AppError{
Code: code,
Message: message,
Cause: err,
}
}
func readFile(path string) ([]byte, error) {
// 模拟读取失败
return nil, fmt.Errorf("文件不存在")
}
func processFile(path string) error {
data, err := readFile(path)
if err != nil {
return wrapError(err, 1001, "读取文件失败")
}
// 处理数据
if len(data) == 0 {
return wrapError(nil, 1002, "文件为空")
}
return nil
}
func main() {
err := processFile("test.txt")
if err != nil {
if appErr, ok := err.(*AppError); ok {
fmt.Printf("应用错误:代码=%d, 消息=%s\n", appErr.Code, appErr.Message)
if appErr.Cause != nil {
fmt.Printf("根本原因:%v\n", appErr.Cause)
}
} else {
fmt.Println("未知错误:", err)
}
}
}
```
---
## 4.7 常见陷阱与最佳实践
### 4.7.1 闭包陷阱总结
1. **循环变量捕获**:循环中使用闭包时,变量会共享
2. **内存泄漏**:闭包捕获大对象导致无法回收
3. **延迟求值**:注意 defer 中参数的求值时机
### 4.7.2 defer 陷阱总结
1. **循环中 defer**:可能导致资源耗尽
2. **返回值修改**:只能修改命名返回值
3. **掩盖错误**recover 可能掩盖真正的 bug
### 4.7.3 接口陷阱总结
1. **空接口滥用**:过度使用 `interface{}` 失去类型安全
2. **接口过大**:定义太多方法的接口难以实现
3. **值 vs 指针**:值类型实现接口,指针类型不实现(反之亦然)
```go
type S struct{}
func (s S) Method() {}
var _ interface{ Method() } = S{} // 正确
var _ interface{ Method() } = &S{} // 正确
// var _ interface{ Method() } = (*S)(nil) // 错误nil 指针不实现
```
### 4.7.4 最佳实践
1. **优先使用错误返回**panic 仅用于不可恢复错误
2. **小接口**:定义最小必要的接口方法
3. **闭包谨慎**:避免捕获大对象,循环中注意变量作用域
4. **defer 适度**:仅在需要清理资源时使用
5. **类型断言安全**:使用 `ok` 模式避免 panic
---
## 4.8 课后练习
1. **闭包计数器**:实现一个支持 `increment()``decrement()``reset()` 的计数器
2. **中间件框架**:实现一个简单的 HTTP 中间件框架
3. **错误包装**:实现一个支持错误链包装的工具函数
4. **接口组合**:设计一组小接口,组合成复杂功能
5. **defer 测试**:编写测试验证 defer 的执行顺序和参数求值时机
## 4.9 下一步
完成本章后,你将进入第五章:**并发编程**,深入学习 Go 最强大的特性——Goroutine 和 Channel以及并发模式、同步原语和并发最佳实践。
---
**代码仓库位置**https://giter.top/openclaw/test/tree/main/chapters/chapter-4
**下一章预告**Goroutine 原理、Channel 通信模式、sync 包、并发设计模式、竞态检测

View File

@@ -0,0 +1,3 @@
module go-tutorial
go 1.21

429
chapters/chapter-4/main.go Normal file
View File

@@ -0,0 +1,429 @@
package main
import (
"fmt"
"os"
"time"
)
// 4.1 函数基础
func add(a, b int) int {
return a + b
}
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("除数不能为零")
}
return a / b, nil
}
func divideNamed(a, b float64) (result float64, err error) {
if b == 0 {
err = fmt.Errorf("除数不能为零")
return
}
result = a / b
return
}
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
func functionBasics() {
fmt.Println("=== 函数基础 ===")
fmt.Println("add(3, 4):", add(3, 4))
result, err := divide(10, 2)
if err != nil {
fmt.Println("错误:", err)
} else {
fmt.Printf("10 / 2 = %.2f\n", result)
}
result2, _ := divideNamed(20, 4)
fmt.Printf("20 / 4 = %.2f\n", result2)
fmt.Println("sum(1,2,3,4,5):", sum(1, 2, 3, 4, 5))
nums := []int{10, 20, 30}
fmt.Println("sum(nums...):", sum(nums...))
}
// 4.2 闭包
func createCounter() func() int {
count := 0
return func() int {
count++
return count
}
}
func createMultiplier(factor int) func(int) int {
return func(x int) int {
return x * factor
}
}
func closureLoopBug() {
funcs := make([]func(), 3)
for i := 0; i < 3; i++ {
funcs[i] = func() {
fmt.Print(i, " ")
}
}
fmt.Print("Bug: ")
for _, f := range funcs {
f()
}
fmt.Println()
}
func closureLoopFix() {
funcs := make([]func(), 3)
for i := 0; i < 3; i++ {
i := i
funcs[i] = func() {
fmt.Print(i, " ")
}
}
fmt.Print("Fix: ")
for _, f := range funcs {
f()
}
fmt.Println()
}
func closureDemo() {
fmt.Println("\n=== 闭包示例 ===")
counter := createCounter()
fmt.Println("counter():", counter()) // 1
fmt.Println("counter():", counter()) // 2
fmt.Println("counter():", counter()) // 3
double := createMultiplier(2)
triple := createMultiplier(3)
fmt.Println("double(5):", double(5)) // 10
fmt.Println("triple(5):", triple(5)) // 15
closureLoopBug()
closureLoopFix()
}
// 4.3 defer
func deferDemo() {
fmt.Println("\n=== defer 示例 ===")
defer fmt.Println("延迟 1")
defer fmt.Println("延迟 2")
fmt.Println("立即执行")
// defer 参数求值
i := 0
defer fmt.Println("defer 时求值 i =", i)
i = 10
// 闭包 defer
defer func() {
fmt.Println("执行时求值 i =", i)
}()
fmt.Println("defer 结束")
}
func deferLoopDemo() {
fmt.Println("\n=== defer 循环陷阱 ===")
// 错误:循环中 defer
for i := 0; i < 3; i++ {
f, err := os.Create(fmt.Sprintf("temp%d.txt", i))
if err != nil {
fmt.Println("创建文件失败:", err)
continue
}
defer f.Close() // 所有 defer 在函数结束时执行
f.WriteString("test")
}
// 正确:立即执行
for i := 0; i < 3; i++ {
func() {
f, err := os.Create(fmt.Sprintf("temp2_%d.txt", i))
if err != nil {
return
}
defer f.Close()
f.WriteString("test")
}()
}
fmt.Println("文件操作完成")
}
// 4.4 panic 和 recover
func panicDemo() {
fmt.Println("\n=== panic 和 recover ===")
defer func() {
if r := recover(); r != nil {
fmt.Println("捕获 panic:", r)
}
}()
fmt.Println("开始")
panic("发生错误")
fmt.Println("不会执行")
}
type MyError struct {
Code int
Message string
}
func (e MyError) Error() string {
return fmt.Sprintf("错误码 %d: %s", e.Code, e.Message)
}
func safeDivide(a, b int) int {
if b == 0 {
panic(MyError{Code: 1001, Message: "除数不能为零"})
}
return a / b
}
func handlePanic() {
defer func() {
if r := recover(); r != nil {
if err, ok := r.(MyError); ok {
fmt.Printf("自定义错误:代码=%d, 消息=%s\n", err.Code, err.Message)
} else {
fmt.Printf("未知 panic: %v\n", r)
}
}
}()
safeDivide(10, 0)
}
func panicRecoverDemo() {
panicDemo()
handlePanic()
}
// 4.5 接口
type Speaker interface {
Speak() string
}
type Dog struct {
Name string
}
func (d Dog) Speak() string {
return d.Name + " 汪汪叫"
}
type Cat struct {
Name string
}
func (c Cat) Speak() string {
return c.Name + " 喵喵叫"
}
func makeSound(s Speaker) {
fmt.Println(s.Speak())
}
func typeAssertionDemo() {
fmt.Println("\n=== 类型断言 ===")
var v interface{} = "hello"
// 基本断言
if s, ok := v.(string); ok {
fmt.Println("是字符串:", s)
}
// 类型开关
switch t := v.(type) {
case int:
fmt.Printf("整数:%d\n", t)
case string:
fmt.Printf("字符串:%s\n", t)
default:
fmt.Printf("未知类型:%T\n", t)
}
}
func interfaceDemo() {
dog := Dog{Name: "旺财"}
cat := Cat{Name: "咪咪"}
makeSound(dog)
makeSound(cat)
typeAssertionDemo()
}
// 4.6 综合案例:插件系统
type Plugin interface {
Name() string
Run() error
}
type HelloPlugin struct{}
func (h HelloPlugin) Name() string {
return "HelloPlugin"
}
func (h HelloPlugin) Run() error {
fmt.Println("Hello from plugin!")
return nil
}
type MathPlugin struct{}
func (m MathPlugin) Name() string {
return "MathPlugin"
}
func (m MathPlugin) Run() error {
fmt.Printf("2 + 2 = %d\n", 2+2)
return nil
}
func pluginDemo() {
fmt.Println("\n=== 插件系统 ===")
plugins := []Plugin{
HelloPlugin{},
MathPlugin{},
}
for _, p := range plugins {
fmt.Printf("加载插件:%s\n", p.Name())
if err := p.Run(); err != nil {
fmt.Println("插件运行失败:", err)
}
}
}
// 4.6 综合案例:中间件链
type Middleware func(Handler) Handler
type Handler func(string) string
func logging(next Handler) Handler {
return func(input string) string {
fmt.Printf("[LOG] 输入:%s\n", input)
result := next(input)
fmt.Printf("[LOG] 输出:%s\n", result)
return result
}
}
func timing(next Handler) Handler {
return func(input string) string {
start := time.Now()
result := next(input)
fmt.Printf("[TIME] 耗时:%v\n", time.Since(start))
return result
}
}
func auth(next Handler) Handler {
return func(input string) string {
if input == "" {
return "错误:空输入"
}
return next(input)
}
}
func businessLogic(input string) string {
return "处理结果:" + input
}
func middlewareDemo() {
fmt.Println("\n=== 中间件链 ===")
handler := auth(timing(logging(businessLogic)))
result := handler("测试数据")
fmt.Println("最终结果:", result)
}
// 4.6 综合案例:错误包装
type AppError struct {
Code int
Message string
Cause error
}
func (e *AppError) Error() string {
if e.Cause != nil {
return fmt.Sprintf("错误码 %d: %s (原因:%v)", e.Code, e.Message, e.Cause)
}
return fmt.Sprintf("错误码 %d: %s", e.Code, e.Message)
}
func wrapError(err error, code int, message string) error {
if err == nil {
return nil
}
return &AppError{
Code: code,
Message: message,
Cause: err,
}
}
func readFile(path string) ([]byte, error) {
return nil, fmt.Errorf("文件不存在")
}
func processFile(path string) error {
data, err := readFile(path)
if err != nil {
return wrapError(err, 1001, "读取文件失败")
}
if len(data) == 0 {
return wrapError(nil, 1002, "文件为空")
}
return nil
}
func errorHandlingDemo() {
fmt.Println("\n=== 错误处理链 ===")
err := processFile("test.txt")
if err != nil {
if appErr, ok := err.(*AppError); ok {
fmt.Printf("应用错误:代码=%d, 消息=%s\n", appErr.Code, appErr.Message)
if appErr.Cause != nil {
fmt.Printf("根本原因:%v\n", appErr.Cause)
}
} else {
fmt.Println("未知错误:", err)
}
}
}
func main() {
functionBasics()
closureDemo()
deferDemo()
deferLoopDemo()
panicRecoverDemo()
interfaceDemo()
pluginDemo()
middlewareDemo()
errorHandlingDemo()
}