diff --git a/chapters/chapter-4-functions-interfaces.md b/chapters/chapter-4-functions-interfaces.md new file mode 100644 index 0000000..61b3907 --- /dev/null +++ b/chapters/chapter-4-functions-interfaces.md @@ -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 执行 + } +} +``` + +#### 陷阱 2:defer 掩盖错误 + +```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+ 可以使用 any(interface{}的别名) +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 包、并发设计模式、竞态检测 diff --git a/chapters/chapter-4/go.mod b/chapters/chapter-4/go.mod new file mode 100644 index 0000000..9ff1861 --- /dev/null +++ b/chapters/chapter-4/go.mod @@ -0,0 +1,3 @@ +module go-tutorial + +go 1.21 diff --git a/chapters/chapter-4/main.go b/chapters/chapter-4/main.go new file mode 100644 index 0000000..585f7e7 --- /dev/null +++ b/chapters/chapter-4/main.go @@ -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() +}