This commit is contained in:
2025-08-24 11:24:52 +08:00
parent ec23aa5c26
commit 61e51ad014
12 changed files with 11554 additions and 4 deletions

View File

@@ -59,27 +59,27 @@
- _需求: 4.1, 4.2, 4.3_ - _需求: 4.1, 4.2, 4.3_
- [ ] 6. 实现接口学习模块 - [ ] 6. 实现接口学习模块
- [ ] 6.1 创建接口基础示例 - [x] 6.1 创建接口基础示例
- 编写 05-interfaces/01-basic-interfaces.go展示接口的定义和实现 - 编写 05-interfaces/01-basic-interfaces.go展示接口的定义和实现
- 编写 05-interfaces/02-empty-interface.go演示空接口的使用 - 编写 05-interfaces/02-empty-interface.go演示空接口的使用
- 编写 05-interfaces/03-type-assertions.go展示类型断言的使用 - 编写 05-interfaces/03-type-assertions.go展示类型断言的使用
- _需求: 3.2_ - _需求: 3.2_
- [ ] 7. 实现并发编程学习模块 - [ ] 7. 实现并发编程学习模块
- [ ] 7.1 创建 Goroutine 和 Channel 示例 - [x] 7.1 创建 Goroutine 和 Channel 示例
- 编写 06-concurrency/01-goroutines.go展示 goroutine 的基础使用 - 编写 06-concurrency/01-goroutines.go展示 goroutine 的基础使用
- 编写 06-concurrency/02-channels.go演示 channel 的各种操作 - 编写 06-concurrency/02-channels.go演示 channel 的各种操作
- 编写 06-concurrency/03-select.go展示 select 语句的使用 - 编写 06-concurrency/03-select.go展示 select 语句的使用
- _需求: 5.1, 5.2, 5.3_ - _需求: 5.1, 5.2, 5.3_
- [ ] 7.2 创建同步和高级并发示例 - [x] 7.2 创建同步和高级并发示例
- 编写 06-concurrency/04-sync-package.go展示 sync 包的使用方法 - 编写 06-concurrency/04-sync-package.go展示 sync 包的使用方法
- 编写 06-concurrency/05-worker-pools.go演示工作池模式 - 编写 06-concurrency/05-worker-pools.go演示工作池模式
- 提供避免竞态条件的最佳实践示例 - 提供避免竞态条件的最佳实践示例
- _需求: 5.1, 5.2, 5.3_ - _需求: 5.1, 5.2, 5.3_
- [ ] 8. 实现错误处理学习模块 - [ ] 8. 实现错误处理学习模块
- [ ] 8.1 创建错误处理示例 - [x] 8.1 创建错误处理示例
- 编写 07-error-handling/01-basic-errors.go展示基本错误处理 - 编写 07-error-handling/01-basic-errors.go展示基本错误处理
- 编写 07-error-handling/02-custom-errors.go演示自定义错误类型 - 编写 07-error-handling/02-custom-errors.go演示自定义错误类型
- 编写 07-error-handling/03-panic-recover.go展示 panic 和 recover 的使用 - 编写 07-error-handling/03-panic-recover.go展示 panic 和 recover 的使用

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,981 @@
/*
02-empty-interface.go - Go 语言空接口详解
学习目标:
1. 理解空接口的概念和特性
2. 掌握空接口的使用场景
3. 学会空接口的类型断言
4. 了解空接口的性能考虑
5. 掌握空接口的实际应用
知识点:
- 空接口的定义 interface{}
- 空接口可以持有任何类型的值
- 空接口的类型断言和类型判断
- 空接口在泛型编程中的应用
- 空接口的性能影响
- 空接口的最佳实践
*/
package main
import (
"fmt"
"reflect"
"strconv"
)
func main() {
fmt.Println("=== Go 语言空接口详解 ===\n")
// 演示空接口的基本概念
demonstrateBasicEmptyInterface()
// 演示空接口的类型断言
demonstrateTypeAssertion()
// 演示空接口的类型判断
demonstrateTypeSwitch()
// 演示空接口的实际应用
demonstratePracticalUsage()
// 演示空接口的高级用法
demonstrateAdvancedUsage()
// 演示空接口的性能考虑
demonstratePerformanceConsiderations()
// 演示空接口的最佳实践
demonstrateBestPractices()
}
// demonstrateBasicEmptyInterface 演示空接口的基本概念
func demonstrateBasicEmptyInterface() {
fmt.Println("1. 空接口的基本概念:")
// 空接口的基本特性
fmt.Printf(" 空接口的基本特性:\n")
fmt.Printf(" - interface{} 不包含任何方法\n")
fmt.Printf(" - 可以持有任何类型的值\n")
fmt.Printf(" - 相当于其他语言中的 Object 或 Any\n")
fmt.Printf(" - 零值是 nil\n")
fmt.Printf(" - 运行时类型信息保存在接口中\n")
// 基本空接口示例
fmt.Printf(" 基本空接口示例:\n")
var empty interface{}
fmt.Printf(" 空接口零值: %v\n", empty)
fmt.Printf(" 空接口 == nil: %t\n", empty == nil)
// 存储不同类型的值
empty = 42
fmt.Printf(" 存储整数: %v (类型: %T)\n", empty, empty)
empty = "Hello, World!"
fmt.Printf(" 存储字符串: %v (类型: %T)\n", empty, empty)
empty = 3.14159
fmt.Printf(" 存储浮点数: %v (类型: %T)\n", empty, empty)
empty = true
fmt.Printf(" 存储布尔值: %v (类型: %T)\n", empty, empty)
empty = []int{1, 2, 3, 4, 5}
fmt.Printf(" 存储切片: %v (类型: %T)\n", empty, empty)
empty = map[string]int{"a": 1, "b": 2}
fmt.Printf(" 存储映射: %v (类型: %T)\n", empty, empty)
// 存储结构体
type Person struct {
Name string
Age int
}
empty = Person{Name: "Alice", Age: 30}
fmt.Printf(" 存储结构体: %v (类型: %T)\n", empty, empty)
// 存储指针
person := &Person{Name: "Bob", Age: 25}
empty = person
fmt.Printf(" 存储指针: %v (类型: %T)\n", empty, empty)
// 存储函数
empty = func(x int) int { return x * 2 }
fmt.Printf(" 存储函数: %v (类型: %T)\n", empty, empty)
fmt.Println()
}
// demonstrateTypeAssertion 演示空接口的类型断言
func demonstrateTypeAssertion() {
fmt.Println("2. 空接口的类型断言:")
fmt.Printf(" 类型断言用于从接口中提取具体类型的值\n")
// 基本类型断言
fmt.Printf(" 基本类型断言:\n")
var value interface{} = "Hello, Go!"
// 安全的类型断言
if str, ok := value.(string); ok {
fmt.Printf(" 类型断言成功: %s (长度: %d)\n", str, len(str))
} else {
fmt.Printf(" 类型断言失败\n")
}
// 不安全的类型断言(可能 panic
str := value.(string)
fmt.Printf(" 直接类型断言: %s\n", str)
// 类型断言失败的情况
fmt.Printf(" 类型断言失败的情况:\n")
value = 42
if str, ok := value.(string); ok {
fmt.Printf(" 字符串断言成功: %s\n", str)
} else {
fmt.Printf(" 字符串断言失败,实际类型: %T\n", value)
}
// 断言为整数
if num, ok := value.(int); ok {
fmt.Printf(" 整数断言成功: %d\n", num)
}
// 多种类型断言
fmt.Printf(" 多种类型断言:\n")
values := []interface{}{
42,
"Hello",
3.14,
true,
[]int{1, 2, 3},
map[string]int{"key": 100},
}
for i, v := range values {
fmt.Printf(" 值 %d (%v):\n", i+1, v)
// 尝试不同的类型断言
if intVal, ok := v.(int); ok {
fmt.Printf(" 整数: %d\n", intVal)
} else if strVal, ok := v.(string); ok {
fmt.Printf(" 字符串: %s\n", strVal)
} else if floatVal, ok := v.(float64); ok {
fmt.Printf(" 浮点数: %.2f\n", floatVal)
} else if boolVal, ok := v.(bool); ok {
fmt.Printf(" 布尔值: %t\n", boolVal)
} else {
fmt.Printf(" 其他类型: %T\n", v)
}
}
fmt.Println()
}
// demonstrateTypeSwitch 演示空接口的类型判断
func demonstrateTypeSwitch() {
fmt.Println("3. 空接口的类型判断:")
fmt.Printf(" 类型 switch 是处理空接口的优雅方式\n")
// 基本类型 switch
fmt.Printf(" 基本类型 switch:\n")
values := []interface{}{
42,
"Hello, World!",
3.14159,
true,
[]int{1, 2, 3, 4, 5},
map[string]int{"a": 1, "b": 2},
nil,
struct{ Name string }{"Alice"},
}
for i, value := range values {
fmt.Printf(" 值 %d: ", i+1)
processValue(value)
}
// 复杂类型 switch
fmt.Printf(" 复杂类型 switch:\n")
complexValues := []interface{}{
Person{Name: "Alice", Age: 30},
&Person{Name: "Bob", Age: 25},
Employee{Person: Person{Name: "Charlie", Age: 35}, Position: "Developer"},
[]Person{{Name: "David", Age: 28}},
make(chan int),
func() { fmt.Println("函数") },
}
for i, value := range complexValues {
fmt.Printf(" 复杂值 %d: ", i+1)
processComplexValue(value)
}
// 类型 switch 的实际应用
fmt.Printf(" 类型 switch 的实际应用:\n")
// JSON 解析模拟
jsonData := map[string]interface{}{
"name": "Alice",
"age": 30,
"salary": 75000.50,
"active": true,
"skills": []interface{}{"Go", "Python", "JavaScript"},
"address": map[string]interface{}{
"city": "New York",
"zipcode": "10001",
},
}
fmt.Printf(" JSON 数据处理:\n")
processJSONData(jsonData, "")
fmt.Println()
}
// demonstratePracticalUsage 演示空接口的实际应用
func demonstratePracticalUsage() {
fmt.Println("4. 空接口的实际应用:")
// 应用1: 通用容器
fmt.Printf(" 应用1 - 通用容器:\n")
container := NewContainer()
// 存储不同类型的数据
container.Add("字符串数据")
container.Add(42)
container.Add(3.14)
container.Add([]int{1, 2, 3})
fmt.Printf(" 容器大小: %d\n", container.Size())
fmt.Printf(" 容器内容:\n")
for i := 0; i < container.Size(); i++ {
item := container.Get(i)
fmt.Printf(" [%d]: %v (%T)\n", i, item, item)
}
// 应用2: 配置系统
fmt.Printf(" 应用2 - 配置系统:\n")
config := NewConfig()
// 设置不同类型的配置
config.Set("app_name", "MyApp")
config.Set("port", 8080)
config.Set("debug", true)
config.Set("timeout", 30.5)
config.Set("features", []string{"auth", "logging", "metrics"})
// 获取配置
fmt.Printf(" 应用名称: %v\n", config.Get("app_name"))
fmt.Printf(" 端口: %v\n", config.Get("port"))
fmt.Printf(" 调试模式: %v\n", config.Get("debug"))
fmt.Printf(" 超时时间: %v\n", config.Get("timeout"))
fmt.Printf(" 功能列表: %v\n", config.Get("features"))
// 类型安全的获取
if port, ok := config.GetInt("port"); ok {
fmt.Printf(" 端口 (类型安全): %d\n", port)
}
if debug, ok := config.GetBool("debug"); ok {
fmt.Printf(" 调试模式 (类型安全): %t\n", debug)
}
// 应用3: 事件系统
fmt.Printf(" 应用3 - 事件系统:\n")
eventBus := NewEventBus()
// 注册事件处理器
eventBus.Subscribe("user_login", func(data interface{}) {
if user, ok := data.(map[string]interface{}); ok {
fmt.Printf(" 用户登录: %s\n", user["username"])
}
})
eventBus.Subscribe("order_created", func(data interface{}) {
if order, ok := data.(map[string]interface{}); ok {
fmt.Printf(" 订单创建: ID=%v, 金额=$%.2f\n",
order["id"], order["amount"])
}
})
// 发布事件
eventBus.Publish("user_login", map[string]interface{}{
"username": "alice",
"ip": "192.168.1.100",
})
eventBus.Publish("order_created", map[string]interface{}{
"id": 12345,
"amount": 99.99,
"items": []string{"laptop", "mouse"},
})
// 应用4: 数据转换
fmt.Printf(" 应用4 - 数据转换:\n")
converter := DataConverter{}
// 转换不同类型的数据
testData := []interface{}{
42,
"123",
3.14,
true,
"false",
[]int{1, 2, 3},
}
for _, data := range testData {
result := converter.ToString(data)
fmt.Printf(" %v (%T) -> \"%s\"\n", data, data, result)
}
fmt.Println()
}
// demonstrateAdvancedUsage 演示空接口的高级用法
func demonstrateAdvancedUsage() {
fmt.Println("5. 空接口的高级用法:")
// 高级用法1: 反射结合空接口
fmt.Printf(" 高级用法1 - 反射结合空接口:\n")
inspector := TypeInspector{}
values := []interface{}{
42,
"Hello",
[]int{1, 2, 3},
map[string]int{"a": 1},
Person{Name: "Alice", Age: 30},
&Person{Name: "Bob", Age: 25},
}
for _, value := range values {
inspector.Inspect(value)
}
// 高级用法2: 深拷贝
fmt.Printf(" 高级用法2 - 深拷贝:\n")
original := map[string]interface{}{
"name": "Alice",
"age": 30,
"address": map[string]interface{}{
"city": "New York",
"zip": "10001",
},
"hobbies": []interface{}{"reading", "swimming"},
}
copied := deepCopy(original)
fmt.Printf(" 原始数据: %v\n", original)
fmt.Printf(" 拷贝数据: %v\n", copied)
// 修改拷贝数据
if copiedMap, ok := copied.(map[string]interface{}); ok {
copiedMap["name"] = "Bob"
if address, ok := copiedMap["address"].(map[string]interface{}); ok {
address["city"] = "Boston"
}
}
fmt.Printf(" 修改后原始: %v\n", original)
fmt.Printf(" 修改后拷贝: %v\n", copied)
// 高级用法3: 序列化和反序列化
fmt.Printf(" 高级用法3 - 序列化和反序列化:\n")
serializer := SimpleSerializer{}
data := map[string]interface{}{
"user_id": 123,
"name": "Alice",
"active": true,
"score": 95.5,
}
// 序列化
serialized := serializer.Serialize(data)
fmt.Printf(" 序列化结果: %s\n", serialized)
// 反序列化
deserialized := serializer.Deserialize(serialized)
fmt.Printf(" 反序列化结果: %v\n", deserialized)
fmt.Println()
}
// demonstratePerformanceConsiderations 演示空接口的性能考虑
func demonstratePerformanceConsiderations() {
fmt.Println("6. 空接口的性能考虑:")
fmt.Printf(" 空接口的性能影响:\n")
fmt.Printf(" - 类型信息存储开销\n")
fmt.Printf(" - 装箱和拆箱成本\n")
fmt.Printf(" - 类型断言的运行时检查\n")
fmt.Printf(" - 垃圾回收压力增加\n")
// 性能对比示例
fmt.Printf(" 性能对比示例:\n")
// 直接类型操作
var directSum int
for i := 0; i < 1000; i++ {
directSum += i
}
fmt.Printf(" 直接类型操作结果: %d\n", directSum)
// 空接口操作
var interfaceSum int
var values []interface{}
for i := 0; i < 1000; i++ {
values = append(values, i)
}
for _, v := range values {
if num, ok := v.(int); ok {
interfaceSum += num
}
}
fmt.Printf(" 空接口操作结果: %d\n", interfaceSum)
// 内存使用对比
fmt.Printf(" 内存使用对比:\n")
// 直接存储
directSlice := make([]int, 1000)
for i := range directSlice {
directSlice[i] = i
}
// 接口存储
interfaceSlice := make([]interface{}, 1000)
for i := range interfaceSlice {
interfaceSlice[i] = i
}
fmt.Printf(" 直接存储切片长度: %d\n", len(directSlice))
fmt.Printf(" 接口存储切片长度: %d\n", len(interfaceSlice))
fmt.Printf(" 注意: 接口存储会有额外的内存开销\n")
fmt.Println()
}
// demonstrateBestPractices 演示空接口的最佳实践
func demonstrateBestPractices() {
fmt.Println("7. 空接口的最佳实践:")
fmt.Printf(" 最佳实践原则:\n")
fmt.Printf(" 1. 避免过度使用空接口\n")
fmt.Printf(" 2. 优先使用具体类型或定义的接口\n")
fmt.Printf(" 3. 使用类型断言时要检查成功与否\n")
fmt.Printf(" 4. 考虑使用泛型替代空接口Go 1.18+\n")
fmt.Printf(" 5. 在 API 边界谨慎使用空接口\n")
// 好的实践示例
fmt.Printf(" 好的实践示例:\n")
// 1. 明确的接口定义
fmt.Printf(" 1. 使用明确的接口而不是空接口:\n")
var printer Printer = ConsolePrinter{}
printer.Print("使用明确接口的消息")
// 2. 类型安全的容器
fmt.Printf(" 2. 类型安全的容器:\n")
stringContainer := NewTypedContainer[string]()
stringContainer.Add("Hello")
stringContainer.Add("World")
fmt.Printf(" 字符串容器: %v\n", stringContainer.GetAll())
intContainer := NewTypedContainer[int]()
intContainer.Add(1)
intContainer.Add(2)
intContainer.Add(3)
fmt.Printf(" 整数容器: %v\n", intContainer.GetAll())
// 3. 错误处理
fmt.Printf(" 3. 正确的错误处理:\n")
result, err := safeTypeAssertion("Hello, World!", "string")
if err != nil {
fmt.Printf(" 类型断言错误: %v\n", err)
} else {
fmt.Printf(" 类型断言成功: %v\n", result)
}
result, err = safeTypeAssertion(42, "string")
if err != nil {
fmt.Printf(" 类型断言错误: %v\n", err)
} else {
fmt.Printf(" 类型断言成功: %v\n", result)
}
// 避免的反模式
fmt.Printf(" 避免的反模式:\n")
fmt.Printf(" - 函数参数和返回值过度使用 interface{}\n")
fmt.Printf(" - 不检查类型断言的成功与否\n")
fmt.Printf(" - 在性能敏感的代码中大量使用空接口\n")
fmt.Printf(" - 用空接口替代适当的类型设计\n")
fmt.Println()
}
// ========== 类型定义 ==========
// 基本结构体
type Person struct {
Name string
Age int
}
type Employee struct {
Person
Position string
}
// 打印器接口
type Printer interface {
Print(message string)
}
type ConsolePrinter struct{}
func (cp ConsolePrinter) Print(message string) {
fmt.Printf(" [控制台] %s\n", message)
}
// ========== 实用工具类型 ==========
// 通用容器
type Container struct {
items []interface{}
}
func NewContainer() *Container {
return &Container{items: make([]interface{}, 0)}
}
func (c *Container) Add(item interface{}) {
c.items = append(c.items, item)
}
func (c *Container) Get(index int) interface{} {
if index >= 0 && index < len(c.items) {
return c.items[index]
}
return nil
}
func (c *Container) Size() int {
return len(c.items)
}
// 配置系统
type Config struct {
data map[string]interface{}
}
func NewConfig() *Config {
return &Config{data: make(map[string]interface{})}
}
func (c *Config) Set(key string, value interface{}) {
c.data[key] = value
}
func (c *Config) Get(key string) interface{} {
return c.data[key]
}
func (c *Config) GetString(key string) (string, bool) {
if value, exists := c.data[key]; exists {
if str, ok := value.(string); ok {
return str, true
}
}
return "", false
}
func (c *Config) GetInt(key string) (int, bool) {
if value, exists := c.data[key]; exists {
if num, ok := value.(int); ok {
return num, true
}
}
return 0, false
}
func (c *Config) GetBool(key string) (bool, bool) {
if value, exists := c.data[key]; exists {
if b, ok := value.(bool); ok {
return b, true
}
}
return false, false
}
// 事件系统
type EventBus struct {
handlers map[string][]func(interface{})
}
func NewEventBus() *EventBus {
return &EventBus{handlers: make(map[string][]func(interface{}))}
}
func (eb *EventBus) Subscribe(event string, handler func(interface{})) {
eb.handlers[event] = append(eb.handlers[event], handler)
}
func (eb *EventBus) Publish(event string, data interface{}) {
if handlers, exists := eb.handlers[event]; exists {
for _, handler := range handlers {
handler(data)
}
}
}
// 数据转换器
type DataConverter struct{}
func (dc DataConverter) ToString(value interface{}) string {
switch v := value.(type) {
case string:
return v
case int:
return strconv.Itoa(v)
case float64:
return strconv.FormatFloat(v, 'f', -1, 64)
case bool:
return strconv.FormatBool(v)
case []int:
result := "["
for i, num := range v {
if i > 0 {
result += ", "
}
result += strconv.Itoa(num)
}
result += "]"
return result
default:
return fmt.Sprintf("%v", v)
}
}
// 类型检查器
type TypeInspector struct{}
func (ti TypeInspector) Inspect(value interface{}) {
if value == nil {
fmt.Printf(" nil 值\n")
return
}
t := reflect.TypeOf(value)
v := reflect.ValueOf(value)
fmt.Printf(" 类型: %s, 种类: %s, 值: %v\n", t.String(), t.Kind().String(), value)
switch t.Kind() {
case reflect.Struct:
fmt.Printf(" 结构体字段数: %d\n", t.NumField())
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
fieldValue := v.Field(i)
fmt.Printf(" %s: %v (%s)\n", field.Name, fieldValue.Interface(), field.Type)
}
case reflect.Ptr:
fmt.Printf(" 指针指向: %s\n", t.Elem().String())
if !v.IsNil() {
fmt.Printf(" 指针值: %v\n", v.Elem().Interface())
}
case reflect.Slice:
fmt.Printf(" 切片长度: %d, 容量: %d\n", v.Len(), v.Cap())
fmt.Printf(" 元素类型: %s\n", t.Elem().String())
case reflect.Map:
fmt.Printf(" 映射长度: %d\n", v.Len())
fmt.Printf(" 键类型: %s, 值类型: %s\n", t.Key().String(), t.Elem().String())
}
}
// 简单序列化器
type SimpleSerializer struct{}
func (ss SimpleSerializer) Serialize(data interface{}) string {
switch v := data.(type) {
case map[string]interface{}:
result := "{"
first := true
for key, value := range v {
if !first {
result += ", "
}
result += fmt.Sprintf("\"%s\": %s", key, ss.serializeValue(value))
first = false
}
result += "}"
return result
default:
return ss.serializeValue(data)
}
}
func (ss SimpleSerializer) serializeValue(value interface{}) string {
switch v := value.(type) {
case string:
return fmt.Sprintf("\"%s\"", v)
case int:
return strconv.Itoa(v)
case float64:
return strconv.FormatFloat(v, 'f', -1, 64)
case bool:
return strconv.FormatBool(v)
default:
return fmt.Sprintf("\"%v\"", v)
}
}
func (ss SimpleSerializer) Deserialize(data string) interface{} {
// 简化的反序列化,实际应用中应该使用 JSON 包
if data == "true" {
return true
}
if data == "false" {
return false
}
if num, err := strconv.Atoi(data); err == nil {
return num
}
if num, err := strconv.ParseFloat(data, 64); err == nil {
return num
}
return data
}
// 类型安全的泛型容器Go 1.18+
type TypedContainer[T any] struct {
items []T
}
func NewTypedContainer[T any]() *TypedContainer[T] {
return &TypedContainer[T]{items: make([]T, 0)}
}
func (tc *TypedContainer[T]) Add(item T) {
tc.items = append(tc.items, item)
}
func (tc *TypedContainer[T]) Get(index int) T {
var zero T
if index >= 0 && index < len(tc.items) {
return tc.items[index]
}
return zero
}
func (tc *TypedContainer[T]) GetAll() []T {
return tc.items
}
// ========== 辅助函数 ==========
// 处理值的类型 switch
func processValue(value interface{}) {
switch v := value.(type) {
case nil:
fmt.Printf("nil 值\n")
case int:
fmt.Printf("整数: %d\n", v)
case string:
fmt.Printf("字符串: \"%s\" (长度: %d)\n", v, len(v))
case float64:
fmt.Printf("浮点数: %.3f\n", v)
case bool:
fmt.Printf("布尔值: %t\n", v)
case []int:
fmt.Printf("整数切片: %v (长度: %d)\n", v, len(v))
case map[string]int:
fmt.Printf("字符串到整数的映射: %v (大小: %d)\n", v, len(v))
default:
fmt.Printf("未知类型: %T, 值: %v\n", v, v)
}
}
// 处理复杂值的类型 switch
func processComplexValue(value interface{}) {
switch v := value.(type) {
case Person:
fmt.Printf("Person 结构体: %s (%d岁)\n", v.Name, v.Age)
case *Person:
fmt.Printf("Person 指针: %s (%d岁)\n", v.Name, v.Age)
case Employee:
fmt.Printf("Employee 结构体: %s - %s\n", v.Name, v.Position)
case []Person:
fmt.Printf("Person 切片: %d 个人\n", len(v))
case chan int:
fmt.Printf("整数通道\n")
case func():
fmt.Printf("无参数函数\n")
default:
fmt.Printf("其他复杂类型: %T\n", v)
}
}
// 处理 JSON 数据
func processJSONData(data map[string]interface{}, indent string) {
for key, value := range data {
fmt.Printf("%s %s: ", indent, key)
switch v := value.(type) {
case string:
fmt.Printf("\"%s\" (字符串)\n", v)
case float64:
fmt.Printf("%.2f (数字)\n", v)
case bool:
fmt.Printf("%t (布尔值)\n", v)
case []interface{}:
fmt.Printf("数组 [%d 个元素]\n", len(v))
for i, item := range v {
fmt.Printf("%s [%d]: %v (%T)\n", indent, i, item, item)
}
case map[string]interface{}:
fmt.Printf("对象 {%d 个字段}\n", len(v))
processJSONData(v, indent+" ")
default:
fmt.Printf("%v (%T)\n", v, v)
}
}
}
// 深拷贝函数
func deepCopy(original interface{}) interface{} {
switch v := original.(type) {
case map[string]interface{}:
copied := make(map[string]interface{})
for key, value := range v {
copied[key] = deepCopy(value)
}
return copied
case []interface{}:
copied := make([]interface{}, len(v))
for i, value := range v {
copied[i] = deepCopy(value)
}
return copied
default:
// 基本类型直接返回(值拷贝)
return v
}
}
// 安全的类型断言
func safeTypeAssertion(value interface{}, expectedType string) (interface{}, error) {
switch expectedType {
case "string":
if str, ok := value.(string); ok {
return str, nil
}
return nil, fmt.Errorf("期望 string 类型,实际是 %T", value)
case "int":
if num, ok := value.(int); ok {
return num, nil
}
return nil, fmt.Errorf("期望 int 类型,实际是 %T", value)
case "bool":
if b, ok := value.(bool); ok {
return b, nil
}
return nil, fmt.Errorf("期望 bool 类型,实际是 %T", value)
default:
return nil, fmt.Errorf("不支持的类型: %s", expectedType)
}
}
/*
运行这个程序:
go run 02-empty-interface.go
学习要点:
1. 空接口 interface{} 可以持有任何类型的值
2. 空接口是 Go 语言中最通用的类型
3. 使用类型断言从空接口中提取具体类型的值
4. 类型 switch 是处理空接口的优雅方式
5. 空接口在泛型编程和动态类型处理中很有用
空接口的特性:
1. 通用性:可以存储任何类型的值
2. 类型安全:通过类型断言保证类型安全
3. 运行时类型信息:保存值的动态类型信息
4. 零值:空接口的零值是 nil
5. 性能开销:有装箱拆箱的成本
类型断言:
1. 安全断言value.(Type) 返回值和布尔标志
2. 不安全断言value.(Type) 只返回值,失败时 panic
3. 类型 switchswitch value.(type) 处理多种类型
4. 类型检查:使用 ok 模式检查断言是否成功
常见应用场景:
1. 通用容器和集合
2. 配置系统和参数传递
3. JSON 和其他格式的数据处理
4. 事件系统和消息传递
5. 插件系统和动态加载
6. 序列化和反序列化
7. 反射和元编程
性能考虑:
1. 装箱开销:基本类型存储到接口需要装箱
2. 类型断言成本:运行时类型检查有开销
3. 内存使用:接口存储需要额外的类型信息
4. 垃圾回收:可能增加 GC 压力
最佳实践:
1. 避免过度使用空接口
2. 优先使用具体类型或定义的接口
3. 使用类型断言时检查成功与否
4. 考虑使用泛型替代空接口Go 1.18+
5. 在 API 设计中谨慎使用空接口
6. 提供类型安全的包装函数
何时使用空接口:
1. 需要存储不同类型的值
2. 处理动态类型的数据(如 JSON
3. 实现通用的算法或容器
4. 与反射结合使用
5. 临时的类型转换需求
何时避免空接口:
1. 类型在编译时已知
2. 性能敏感的代码
3. 可以用泛型替代的场景
4. API 的公共接口设计
5. 简单的数据传递
注意事项:
1. nil 接口不能调用方法
2. 类型断言失败可能导致 panic
3. 空接口比较需要注意动态类型
4. 过度使用会降低代码的类型安全性
5. 调试时类型信息可能不够清晰
*/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,738 @@
/*
01-goroutines.go - Go 语言 Goroutines 详解
学习目标:
1. 理解 goroutine 的概念和特性
2. 掌握 goroutine 的创建和使用
3. 学会 goroutine 的同步和通信
4. 了解 goroutine 的调度机制
5. 掌握 goroutine 的最佳实践
知识点:
- goroutine 的基本概念
- go 关键字的使用
- goroutine 与线程的区别
- goroutine 的生命周期
- goroutine 泄漏的预防
- 并发安全的考虑
*/
package main
import (
"fmt"
"runtime"
"sync"
"time"
)
func main() {
fmt.Println("=== Go 语言 Goroutines 详解 ===\n")
// 演示基本的 goroutine
demonstrateBasicGoroutines()
// 演示 goroutine 的并发执行
demonstrateConcurrentExecution()
// 演示 goroutine 的同步
demonstrateGoroutineSynchronization()
// 演示 goroutine 的通信
demonstrateGoroutineCommunication()
// 演示 goroutine 池
demonstrateGoroutinePool()
// 演示 goroutine 的生命周期管理
demonstrateGoroutineLifecycle()
// 演示 goroutine 的最佳实践
demonstrateBestPractices()
}
// demonstrateBasicGoroutines 演示基本的 goroutine
func demonstrateBasicGoroutines() {
fmt.Println("1. 基本的 Goroutine:")
// goroutine 的基本概念
fmt.Printf(" Goroutine 的基本概念:\n")
fmt.Printf(" - 轻量级线程,由 Go 运行时管理\n")
fmt.Printf(" - 使用 go 关键字启动\n")
fmt.Printf(" - 栈大小动态增长,初始只有 2KB\n")
fmt.Printf(" - 由 Go 调度器调度,不是操作系统线程\n")
fmt.Printf(" - 可以创建数百万个 goroutine\n")
// 基本 goroutine 示例
fmt.Printf(" 基本 goroutine 示例:\n")
// 普通函数调用
fmt.Printf(" 普通函数调用:\n")
sayHello("World")
sayHello("Go")
// 使用 goroutine
fmt.Printf(" 使用 goroutine:\n")
go sayHello("Goroutine 1")
go sayHello("Goroutine 2")
go sayHello("Goroutine 3")
// 等待 goroutine 完成
time.Sleep(100 * time.Millisecond)
// 匿名函数 goroutine
fmt.Printf(" 匿名函数 goroutine:\n")
for i := 1; i <= 3; i++ {
go func(id int) {
fmt.Printf(" 匿名 goroutine %d 执行\n", id)
}(i)
}
time.Sleep(100 * time.Millisecond)
// 闭包 goroutine
fmt.Printf(" 闭包 goroutine:\n")
message := "Hello from closure"
go func() {
fmt.Printf(" %s\n", message)
}()
time.Sleep(100 * time.Millisecond)
fmt.Println()
}
// demonstrateConcurrentExecution 演示 goroutine 的并发执行
func demonstrateConcurrentExecution() {
fmt.Println("2. Goroutine 的并发执行:")
// 并发执行任务
fmt.Printf(" 并发执行任务:\n")
start := time.Now()
// 串行执行
fmt.Printf(" 串行执行:\n")
serialStart := time.Now()
task("任务1", 200*time.Millisecond)
task("任务2", 200*time.Millisecond)
task("任务3", 200*time.Millisecond)
serialDuration := time.Since(serialStart)
fmt.Printf(" 串行执行耗时: %v\n", serialDuration)
// 并发执行
fmt.Printf(" 并发执行:\n")
concurrentStart := time.Now()
var wg sync.WaitGroup
wg.Add(3)
go func() {
defer wg.Done()
task("并发任务1", 200*time.Millisecond)
}()
go func() {
defer wg.Done()
task("并发任务2", 200*time.Millisecond)
}()
go func() {
defer wg.Done()
task("并发任务3", 200*time.Millisecond)
}()
wg.Wait()
concurrentDuration := time.Since(concurrentStart)
fmt.Printf(" 并发执行耗时: %v\n", concurrentDuration)
// CPU 密集型任务
fmt.Printf(" CPU 密集型任务:\n")
numCPU := runtime.NumCPU()
fmt.Printf(" CPU 核心数: %d\n", numCPU)
// 设置使用的 CPU 核心数
runtime.GOMAXPROCS(numCPU)
cpuStart := time.Now()
var cpuWg sync.WaitGroup
for i := 0; i < numCPU; i++ {
cpuWg.Add(1)
go func(id int) {
defer cpuWg.Done()
result := fibonacci(35)
fmt.Printf(" Goroutine %d: fibonacci(35) = %d\n", id, result)
}(i)
}
cpuWg.Wait()
cpuDuration := time.Since(cpuStart)
fmt.Printf(" CPU 密集型任务耗时: %v\n", cpuDuration)
totalDuration := time.Since(start)
fmt.Printf(" 总耗时: %v\n", totalDuration)
fmt.Println()
}
// demonstrateGoroutineSynchronization 演示 goroutine 的同步
func demonstrateGoroutineSynchronization() {
fmt.Println("3. Goroutine 的同步:")
// 使用 WaitGroup 同步
fmt.Printf(" 使用 WaitGroup 同步:\n")
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
fmt.Printf(" Worker %d 开始工作\n", id)
time.Sleep(time.Duration(id*100) * time.Millisecond)
fmt.Printf(" Worker %d 完成工作\n", id)
}(i)
}
fmt.Printf(" 等待所有 worker 完成...\n")
wg.Wait()
fmt.Printf(" 所有 worker 已完成\n")
// 使用 Mutex 保护共享资源
fmt.Printf(" 使用 Mutex 保护共享资源:\n")
var counter Counter
var counterWg sync.WaitGroup
// 启动多个 goroutine 增加计数器
for i := 0; i < 10; i++ {
counterWg.Add(1)
go func(id int) {
defer counterWg.Done()
for j := 0; j < 1000; j++ {
counter.Increment()
}
fmt.Printf(" Goroutine %d 完成\n", id)
}(i)
}
counterWg.Wait()
fmt.Printf(" 最终计数器值: %d\n", counter.Value())
// 使用 Once 确保只执行一次
fmt.Printf(" 使用 Once 确保只执行一次:\n")
var once sync.Once
var onceWg sync.WaitGroup
for i := 0; i < 5; i++ {
onceWg.Add(1)
go func(id int) {
defer onceWg.Done()
once.Do(func() {
fmt.Printf(" 初始化操作只执行一次 (来自 goroutine %d)\n", id)
})
fmt.Printf(" Goroutine %d 执行完毕\n", id)
}(i)
}
onceWg.Wait()
fmt.Println()
}
// demonstrateGoroutineCommunication 演示 goroutine 的通信
func demonstrateGoroutineCommunication() {
fmt.Println("4. Goroutine 的通信:")
// 使用 channel 通信
fmt.Printf(" 使用 channel 通信:\n")
// 简单的 channel 通信
ch := make(chan string)
go func() {
time.Sleep(100 * time.Millisecond)
ch <- "Hello from goroutine"
}()
message := <-ch
fmt.Printf(" 接收到消息: %s\n", message)
// 生产者-消费者模式
fmt.Printf(" 生产者-消费者模式:\n")
jobs := make(chan int, 5)
results := make(chan int, 5)
// 启动 3 个 worker
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
// 发送 5 个任务
for j := 1; j <= 5; j++ {
jobs <- j
}
close(jobs)
// 收集结果
for r := 1; r <= 5; r++ {
result := <-results
fmt.Printf(" 结果: %d\n", result)
}
// 扇出/扇入模式
fmt.Printf(" 扇出/扇入模式:\n")
input := make(chan int)
output1 := make(chan int)
output2 := make(chan int)
// 扇出:一个输入分发到多个处理器
go func() {
for i := 1; i <= 10; i++ {
input <- i
}
close(input)
}()
// 处理器 1
go func() {
for num := range input {
output1 <- num * 2
}
close(output1)
}()
// 处理器 2
go func() {
for num := range input {
output2 <- num * 3
}
close(output2)
}()
// 扇入:合并多个输出
merged := fanIn(output1, output2)
fmt.Printf(" 合并结果: ")
for result := range merged {
fmt.Printf("%d ", result)
}
fmt.Printf("\n")
fmt.Println()
}
// demonstrateGoroutinePool 演示 goroutine 池
func demonstrateGoroutinePool() {
fmt.Println("5. Goroutine 池:")
// 固定大小的 goroutine 池
fmt.Printf(" 固定大小的 goroutine 池:\n")
const numWorkers = 3
const numJobs = 10
jobs := make(chan Job, numJobs)
results := make(chan Result, numJobs)
// 启动 worker 池
for w := 1; w <= numWorkers; w++ {
go jobWorker(w, jobs, results)
}
// 发送任务
for j := 1; j <= numJobs; j++ {
jobs <- Job{ID: j, Data: fmt.Sprintf("任务数据 %d", j)}
}
close(jobs)
// 收集结果
for r := 1; r <= numJobs; r++ {
result := <-results
fmt.Printf(" %s\n", result.Message)
}
// 动态 goroutine 池
fmt.Printf(" 动态 goroutine 池:\n")
pool := NewWorkerPool(5, 20)
pool.Start()
// 提交任务
for i := 1; i <= 15; i++ {
taskID := i
pool.Submit(func() {
fmt.Printf(" 执行任务 %d\n", taskID)
time.Sleep(100 * time.Millisecond)
})
}
pool.Stop()
fmt.Println()
}
// demonstrateGoroutineLifecycle 演示 goroutine 的生命周期管理
func demonstrateGoroutineLifecycle() {
fmt.Println("6. Goroutine 的生命周期管理:")
// 优雅关闭
fmt.Printf(" 优雅关闭:\n")
done := make(chan bool)
quit := make(chan bool)
go func() {
for {
select {
case <-quit:
fmt.Printf(" 接收到退出信号,正在清理...\n")
time.Sleep(100 * time.Millisecond)
fmt.Printf(" 清理完成\n")
done <- true
return
default:
fmt.Printf(" 工作中...\n")
time.Sleep(200 * time.Millisecond)
}
}
}()
time.Sleep(500 * time.Millisecond)
fmt.Printf(" 发送退出信号\n")
quit <- true
<-done
fmt.Printf(" Goroutine 已优雅退出\n")
// 超时控制
fmt.Printf(" 超时控制:\n")
timeout := time.After(300 * time.Millisecond)
finished := make(chan bool)
go func() {
time.Sleep(500 * time.Millisecond) // 模拟长时间运行的任务
finished <- true
}()
select {
case <-finished:
fmt.Printf(" 任务完成\n")
case <-timeout:
fmt.Printf(" 任务超时\n")
}
// 错误处理
fmt.Printf(" 错误处理:\n")
errorCh := make(chan error, 1)
go func() {
defer func() {
if r := recover(); r != nil {
errorCh <- fmt.Errorf("goroutine panic: %v", r)
}
}()
// 模拟可能 panic 的操作
if time.Now().UnixNano()%2 == 0 {
panic("模拟 panic")
}
fmt.Printf(" 任务正常完成\n")
errorCh <- nil
}()
if err := <-errorCh; err != nil {
fmt.Printf(" 捕获到错误: %v\n", err)
}
fmt.Println()
}
// demonstrateBestPractices 演示 goroutine 的最佳实践
func demonstrateBestPractices() {
fmt.Println("7. Goroutine 的最佳实践:")
fmt.Printf(" 最佳实践原则:\n")
fmt.Printf(" 1. 避免 goroutine 泄漏\n")
fmt.Printf(" 2. 使用 context 进行取消和超时控制\n")
fmt.Printf(" 3. 合理控制 goroutine 数量\n")
fmt.Printf(" 4. 使用 channel 进行通信而不是共享内存\n")
fmt.Printf(" 5. 正确处理 panic 和错误\n")
// 避免 goroutine 泄漏
fmt.Printf(" 避免 goroutine 泄漏:\n")
// 错误示例:可能导致 goroutine 泄漏
fmt.Printf(" 错误示例 - 可能导致泄漏:\n")
leakyCh := make(chan int)
go func() {
// 这个 goroutine 可能永远阻塞
leakyCh <- 42
}()
// 如果不读取 channelgoroutine 会泄漏
// 正确示例:使用缓冲 channel 或确保读取
fmt.Printf(" 正确示例 - 避免泄漏:\n")
safeCh := make(chan int, 1) // 缓冲 channel
go func() {
safeCh <- 42
fmt.Printf(" 安全的 goroutine 完成\n")
}()
<-safeCh
// 使用 defer 清理资源
fmt.Printf(" 使用 defer 清理资源:\n")
var cleanupWg sync.WaitGroup
cleanupWg.Add(1)
go func() {
defer cleanupWg.Done()
defer fmt.Printf(" 资源已清理\n")
fmt.Printf(" 执行任务...\n")
time.Sleep(100 * time.Millisecond)
}()
cleanupWg.Wait()
// 监控 goroutine 数量
fmt.Printf(" 监控 goroutine 数量:\n")
fmt.Printf(" 当前 goroutine 数量: %d\n", runtime.NumGoroutine())
// 启动一些 goroutine
var monitorWg sync.WaitGroup
for i := 0; i < 5; i++ {
monitorWg.Add(1)
go func(id int) {
defer monitorWg.Done()
time.Sleep(100 * time.Millisecond)
}(i)
}
fmt.Printf(" 启动 5 个 goroutine 后: %d\n", runtime.NumGoroutine())
monitorWg.Wait()
fmt.Printf(" goroutine 完成后: %d\n", runtime.NumGoroutine())
fmt.Println()
}
// ========== 辅助函数和类型定义 ==========
// sayHello 简单的问候函数
func sayHello(name string) {
fmt.Printf(" Hello, %s!\n", name)
}
// task 模拟一个耗时任务
func task(name string, duration time.Duration) {
fmt.Printf(" %s 开始执行\n", name)
time.Sleep(duration)
fmt.Printf(" %s 执行完成\n", name)
}
// fibonacci 计算斐波那契数列CPU 密集型任务)
func fibonacci(n int) int {
if n <= 1 {
return n
}
return fibonacci(n-1) + fibonacci(n-2)
}
// Counter 线程安全的计数器
type Counter struct {
mu sync.Mutex
value int
}
func (c *Counter) Increment() {
c.mu.Lock()
defer c.mu.Unlock()
c.value++
}
func (c *Counter) Value() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.value
}
// worker 工作函数
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
fmt.Printf(" Worker %d 开始处理任务 %d\n", id, j)
time.Sleep(100 * time.Millisecond)
results <- j * 2
}
}
// fanIn 扇入函数,合并多个 channel
func fanIn(input1, input2 <-chan int) <-chan int {
output := make(chan int)
go func() {
defer close(output)
for input1 != nil || input2 != nil {
select {
case val, ok := <-input1:
if !ok {
input1 = nil
} else {
output <- val
}
case val, ok := <-input2:
if !ok {
input2 = nil
} else {
output <- val
}
}
}
}()
return output
}
// Job 任务结构
type Job struct {
ID int
Data string
}
// Result 结果结构
type Result struct {
JobID int
Message string
}
// jobWorker 任务处理器
func jobWorker(id int, jobs <-chan Job, results chan<- Result) {
for job := range jobs {
fmt.Printf(" Worker %d 处理任务 %d\n", id, job.ID)
time.Sleep(100 * time.Millisecond)
results <- Result{
JobID: job.ID,
Message: fmt.Sprintf("Worker %d 完成任务 %d: %s", id, job.ID, job.Data),
}
}
}
// WorkerPool 动态工作池
type WorkerPool struct {
maxWorkers int
taskQueue chan func()
quit chan bool
wg sync.WaitGroup
}
// NewWorkerPool 创建新的工作池
func NewWorkerPool(maxWorkers, queueSize int) *WorkerPool {
return &WorkerPool{
maxWorkers: maxWorkers,
taskQueue: make(chan func(), queueSize),
quit: make(chan bool),
}
}
// Start 启动工作池
func (p *WorkerPool) Start() {
for i := 0; i < p.maxWorkers; i++ {
p.wg.Add(1)
go p.worker(i + 1)
}
}
// Submit 提交任务
func (p *WorkerPool) Submit(task func()) {
select {
case p.taskQueue <- task:
default:
fmt.Printf(" 任务队列已满,任务被丢弃\n")
}
}
// Stop 停止工作池
func (p *WorkerPool) Stop() {
close(p.taskQueue)
p.wg.Wait()
}
// worker 工作池的工作函数
func (p *WorkerPool) worker(id int) {
defer p.wg.Done()
for task := range p.taskQueue {
fmt.Printf(" Pool Worker %d 执行任务\n", id)
task()
}
fmt.Printf(" Pool Worker %d 退出\n", id)
}
/*
运行这个程序:
go run 01-goroutines.go
学习要点:
1. Goroutine 是 Go 语言的轻量级线程
2. 使用 go 关键字启动 goroutine
3. Goroutine 之间需要同步和通信机制
4. 使用 WaitGroup、Mutex、Once 等<><E7AD89><EFBFBD>步原语
5. 通过 channel 进行 goroutine 间通信
Goroutine 的特性:
1. 轻量级:初始栈大小只有 2KB
2. 动态增长:栈大小可以动态调整
3. 多路复用:多个 goroutine 可以在少数 OS 线程上运行
4. 协作式调度:由 Go 运行时调度
5. 高效通信:通过 channel 进行通信
同步机制:
1. WaitGroup等待一组 goroutine 完成
2. Mutex互斥锁保护共享资源
3. RWMutex读写锁允许多个读者
4. Once确保函数只执行一次
5. Cond条件变量用于等待条件
通信模式:
1. 简单通信:通过 channel 发送和接收数据
2. 生产者-消费者:使用缓冲 channel
3. 扇出/扇入:一对多和多对一的通信
4. 管道:链式处理数据
5. 工作池:固定数量的 worker 处理任务
最佳实践:
1. 避免 goroutine 泄漏
2. 使用 context 进行取消和超时控制
3. 合理控制 goroutine 数量
4. 使用 channel 进行通信而不是共享内存
5. 正确处理 panic 和错误
6. 使用 defer 清理资源
7. 监控 goroutine 数量
常见陷阱:
1. 忘记等待 goroutine 完成
2. 在循环中使用闭包时的变量捕获问题
3. 无缓冲 channel 导致的死锁
4. goroutine 泄漏
5. 竞态条件
性能考虑:
1. Goroutine 创建成本很低
2. 上下文切换开销小
3. 内存使用效率高
4. 适合 I/O 密集型任务
5. CPU 密集型任务需要考虑 GOMAXPROCS
注意事项:
1. main 函数退出时所有 goroutine 都会终止
2. goroutine 中的 panic 会导致整个程序崩溃
3. 共享变量需要同步保护
4. channel 的关闭只能由发送方执行
5. 避免在 goroutine 中使用全局变量
*/

View File

@@ -0,0 +1,840 @@
/*
02-channels.go - Go 语言 Channels 详解
学习目标:
1. 理解 channel 的概念和特性
2. 掌握 channel 的创建和使用
3. 学会不同类型的 channel
4. 了解 channel 的方向性
5. 掌握 channel 的关闭和检测
知识点:
- channel 的基本概念
- 无缓冲和有缓冲 channel
- channel 的方向性
- channel 的关闭
- range 和 select 与 channel
- channel 的常见模式
*/
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
func main() {
fmt.Println("=== Go 语言 Channels 详解 ===\n")
// 演示基本的 channel
demonstrateBasicChannels()
// 演示缓冲 channel
demonstrateBufferedChannels()
// 演示 channel 的方向性
demonstrateChannelDirections()
// 演示 channel 的关闭
demonstrateChannelClosing()
// 演示 channel 与 range
demonstrateChannelRange()
// 演示 channel 的常见模式
demonstrateChannelPatterns()
// 演示 channel 的高级用法
demonstrateAdvancedChannelUsage()
}
// demonstrateBasicChannels 演示基本的 channel
func demonstrateBasicChannels() {
fmt.Println("1. 基本的 Channel:")
// channel 的基本概念
fmt.Printf(" Channel 的基本概念:\n")
fmt.Printf(" - Go 语言的核心特性,用于 goroutine 间通信\n")
fmt.Printf(" - 类型安全的管道,可以传递特定类型的数据\n")
fmt.Printf(" - 默认是无缓冲的,发送和接收会阻塞\n")
fmt.Printf(" - 遵循 'Don't communicate by sharing memory; share memory by communicating'\n")
// 创建和使用 channel
fmt.Printf(" 创建和使用 channel:\n")
// 创建一个 int 类型的 channel
ch := make(chan int)
// 在 goroutine 中发送数据
go func() {
fmt.Printf(" 发送数据到 channel\n")
ch <- 42
}()
// 从 channel 接收数据
value := <-ch
fmt.Printf(" 从 channel 接收到: %d\n", value)
// 双向通信
fmt.Printf(" 双向通信:\n")
messages := make(chan string)
responses := make(chan string)
// 启动一个 echo 服务
go echoServer(messages, responses)
// 发送消息并接收响应
messages <- "Hello"
response := <-responses
fmt.Printf(" 发送: Hello, 接收: %s\n", response)
messages <- "World"
response = <-responses
fmt.Printf(" 发送: World, 接收: %s\n", response)
// 关闭 channels
close(messages)
close(responses)
// 同步使用 channel
fmt.Printf(" 同步使用 channel:\n")
done := make(chan bool)
go func() {
fmt.Printf(" 执行异步任务...\n")
time.Sleep(200 * time.Millisecond)
fmt.Printf(" 异步任务完成\n")
done <- true
}()
fmt.Printf(" 等待异步任务完成...\n")
<-done
fmt.Printf(" 主程序继续执行\n")
fmt.Println()
}
// demonstrateBufferedChannels 演示缓冲 channel
func demonstrateBufferedChannels() {
fmt.Println("2. 缓冲 Channel:")
// 无缓冲 vs 有缓冲
fmt.Printf(" 无缓冲 vs 有缓冲:\n")
// 无缓冲 channel同步
fmt.Printf(" 无缓冲 channel (同步):\n")
unbuffered := make(chan string)
go func() {
fmt.Printf(" 发送到无缓冲 channel\n")
unbuffered <- "sync message"
fmt.Printf(" 无缓冲 channel 发送完成\n")
}()
time.Sleep(100 * time.Millisecond) // 让 goroutine 先运行
msg := <-unbuffered
fmt.Printf(" 接收到: %s\n", msg)
// 有缓冲 channel异步
fmt.Printf(" 有缓冲 channel (异步):\n")
buffered := make(chan string, 2)
fmt.Printf(" 发送到有缓冲 channel\n")
buffered <- "async message 1"
buffered <- "async message 2"
fmt.Printf(" 有缓冲 channel 发送完成(未阻塞)\n")
fmt.Printf(" 接收到: %s\n", <-buffered)
fmt.Printf(" 接收到: %s\n", <-buffered)
// 缓冲区满时的行为
fmt.Printf(" 缓冲区满时的行为:\n")
fullBuffer := make(chan int, 2)
// 填满缓冲区
fullBuffer <- 1
fullBuffer <- 2
fmt.Printf(" 缓冲区已满 (2/2)\n")
// 尝试再发送一个值(会阻塞)
go func() {
fmt.Printf(" 尝试发送第三个值(会阻塞)\n")
fullBuffer <- 3
fmt.Printf(" 第三个值发送成功\n")
}()
time.Sleep(100 * time.Millisecond)
fmt.Printf(" 接收一个值: %d\n", <-fullBuffer)
time.Sleep(100 * time.Millisecond)
fmt.Printf(" 接收一个值: %d\n", <-fullBuffer)
fmt.Printf(" 接收一个值: %d\n", <-fullBuffer)
// 生产者-消费者模式
fmt.Printf(" 生产者-消费者模式:\n")
const bufferSize = 5
const numProducers = 2
const numConsumers = 3
const numItems = 10
items := make(chan int, bufferSize)
var wg sync.WaitGroup
// 启动生产者
for i := 0; i < numProducers; i++ {
wg.Add(1)
go producer(i+1, items, numItems/numProducers, &wg)
}
// 启动消费者
for i := 0; i < numConsumers; i++ {
wg.Add(1)
go consumer(i+1, items, &wg)
}
// 等待所有生产者完成,然后关闭 channel
go func() {
wg.Wait()
close(items)
}()
// 等待一段时间让消费者处理完所有项目
time.Sleep(500 * time.Millisecond)
fmt.Println()
}
// demonstrateChannelDirections 演示 channel 的方向性
func demonstrateChannelDirections() {
fmt.Println("3. Channel 的方向性:")
// 双向 channel
fmt.Printf(" 双向 channel:\n")
bidirectional := make(chan string)
go func() {
bidirectional <- "双向消息"
}()
message := <-bidirectional
fmt.Printf(" 接收到: %s\n", message)
// 只发送 channel
fmt.Printf(" 只发送 channel:\n")
sendOnly := make(chan int)
go sender(sendOnly)
value := <-sendOnly
fmt.Printf(" 从只发送 channel 接收到: %d\n", value)
// 只接收 channel
fmt.Printf(" 只接收 channel:\n")
receiveOnly := make(chan int, 1)
receiveOnly <- 100
go receiver(receiveOnly)
time.Sleep(100 * time.Millisecond)
// 管道模式
fmt.Printf(" 管道模式:\n")
numbers := make(chan int)
squares := make(chan int)
cubes := make(chan int)
// 启动管道
go generateNumbers(numbers)
go squareNumbers(numbers, squares)
go cubeNumbers(squares, cubes)
// 读取最终结果
for i := 0; i < 5; i++ {
result := <-cubes
fmt.Printf(" 管道结果: %d\n", result)
}
fmt.Println()
}
// demonstrateChannelClosing 演示 channel 的关闭
func demonstrateChannelClosing() {
fmt.Println("4. Channel 的关闭:")
// 基本的 channel 关闭
fmt.Printf(" 基本的 channel 关闭:\n")
ch := make(chan int, 3)
// 发送一些值
ch <- 1
ch <- 2
ch <- 3
// 关闭 channel
close(ch)
// 从已关闭的 channel 读取
for i := 0; i < 4; i++ {
value, ok := <-ch
if ok {
fmt.Printf(" 接收到值: %d\n", value)
} else {
fmt.Printf(" channel 已关闭,接收到零值: %d\n", value)
}
}
// 检测 channel 是否关闭
fmt.Printf(" 检测 channel 是否关闭:\n")
status := make(chan string, 2)
status <- "active"
status <- "inactive"
close(status)
for {
value, ok := <-status
if !ok {
fmt.Printf(" channel 已关闭,退出循环\n")
break
}
fmt.Printf(" 状态: %s\n", value)
}
// 多个发送者的关闭模式
fmt.Printf(" 多个发送者的关闭模式:\n")
data := make(chan int)
done := make(chan bool)
// 启动多个发送者
for i := 1; i <= 3; i++ {
go multipleSender(i, data, done)
}
// 接收数据
go func() {
for value := range data {
fmt.Printf(" 接收到: %d\n", value)
}
fmt.Printf(" 数据接收完成\n")
}()
// 等待一段时间后通知所有发送者停止
time.Sleep(300 * time.Millisecond)
close(done)
// 等待发送者停止后关闭数据 channel
time.Sleep(100 * time.Millisecond)
close(data)
time.Sleep(100 * time.Millisecond)
fmt.Println()
}
// demonstrateChannelRange 演示 channel 与 range
func demonstrateChannelRange() {
fmt.Println("5. Channel 与 Range:")
// 使用 range 遍历 channel
fmt.Printf(" 使用 range 遍历 channel:\n")
numbers := make(chan int)
// 发送数据
go func() {
for i := 1; i <= 5; i++ {
numbers <- i
time.Sleep(50 * time.Millisecond)
}
close(numbers)
}()
// 使用 range 接收数据
for num := range numbers {
fmt.Printf(" 接收到数字: %d\n", num)
}
// 斐波那契数列生成器
fmt.Printf(" 斐波那契数列生成器:\n")
fib := fibonacci(10)
for value := range fib {
fmt.Printf(" 斐波那契: %d\n", value)
}
// 素数生成器
fmt.Printf(" 素数生成器:\n")
primes := sieve(30)
fmt.Printf(" 30 以内的素数: ")
for prime := range primes {
fmt.Printf("%d ", prime)
}
fmt.Printf("\n")
fmt.Println()
}
// demonstrateChannelPatterns 演示 channel 的常见模式
func demonstrateChannelPatterns() {
fmt.Println("6. Channel 的常见模式:")
// 扇出模式(一个输入,多个输出)
fmt.Printf(" 扇出模式:\n")
input := make(chan int)
output1 := make(chan int)
output2 := make(chan int)
output3 := make(chan int)
// 扇出
go fanOut(input, output1, output2, output3)
// 发送数据
go func() {
for i := 1; i <= 6; i++ {
input <- i
}
close(input)
}()
// 接收数据
var wg sync.WaitGroup
wg.Add(3)
go func() {
defer wg.Done()
for value := range output1 {
fmt.Printf(" 输出1: %d\n", value)
}
}()
go func() {
defer wg.Done()
for value := range output2 {
fmt.Printf(" 输出2: %d\n", value)
}
}()
go func() {
defer wg.Done()
for value := range output3 {
fmt.Printf(" 输出3: %d\n", value)
}
}()
wg.Wait()
// 扇入模式(多个输入,一个输出)
fmt.Printf(" 扇入模式:\n")
input1 := make(chan string)
input2 := make(chan string)
input3 := make(chan string)
// 启动输入源
go func() {
for i := 1; i <= 3; i++ {
input1 <- fmt.Sprintf("源1-%d", i)
time.Sleep(100 * time.Millisecond)
}
close(input1)
}()
go func() {
for i := 1; i <= 3; i++ {
input2 <- fmt.Sprintf("源2-%d", i)
time.Sleep(150 * time.Millisecond)
}
close(input2)
}()
go func() {
for i := 1; i <= 3; i++ {
input3 <- fmt.Sprintf("源3-%d", i)
time.Sleep(200 * time.Millisecond)
}
close(input3)
}()
// 扇入
merged := fanInMultiple(input1, input2, input3)
fmt.Printf(" 合并结果:\n")
for result := range merged {
fmt.Printf(" %s\n", result)
}
// 工作池模式
fmt.Printf(" 工作池模式:\n")
jobs := make(chan WorkJob, 10)
results := make(chan WorkResult, 10)
// 启动工作池
const numWorkers = 3
for w := 1; w <= numWorkers; w++ {
go workPoolWorker(w, jobs, results)
}
// 发送任务
for j := 1; j <= 9; j++ {
jobs <- WorkJob{ID: j, Data: fmt.Sprintf("任务-%d", j)}
}
close(jobs)
// 收集结果
for r := 1; r <= 9; r++ {
result := <-results
fmt.Printf(" %s\n", result.Message)
}
fmt.Println()
}
// demonstrateAdvancedChannelUsage 演示 channel 的高级用法
func demonstrateAdvancedChannelUsage() {
fmt.Println("7. Channel 的高级用法:")
// 超时模式
fmt.Printf(" 超时模式:\n")
slowCh := make(chan string)
go func() {
time.Sleep(300 * time.Millisecond)
slowCh <- "慢速响应"
}()
select {
case result := <-slowCh:
fmt.Printf(" 接收到: %s\n", result)
case <-time.After(200 * time.Millisecond):
fmt.Printf(" 操作超时\n")
}
// 非阻塞操作
fmt.Printf(" 非阻塞操作:\n")
nonBlockingCh := make(chan int, 1)
// 非阻塞发送
select {
case nonBlockingCh <- 42:
fmt.Printf(" 非阻塞发送成功\n")
default:
fmt.Printf(" 非阻塞发送失败channel 已满\n")
}
// 非阻塞接收
select {
case value := <-nonBlockingCh:
fmt.Printf(" 非阻塞接收成功: %d\n", value)
default:
fmt.Printf(" 非阻塞接收失败channel 为空\n")
}
// 心跳模式
fmt.Printf(" 心跳模式:\n")
heartbeat := time.NewTicker(100 * time.Millisecond)
defer heartbeat.Stop()
timeout := time.After(350 * time.Millisecond)
for {
select {
case <-heartbeat.C:
fmt.Printf(" 心跳\n")
case <-timeout:
fmt.Printf(" 心跳监控结束\n")
goto heartbeatEnd
}
}
heartbeatEnd:
// 速率限制
fmt.Printf(" 速率限制:\n")
rateLimiter := time.NewTicker(100 * time.Millisecond)
defer rateLimiter.Stop()
requests := make(chan int, 5)
for i := 1; i <= 5; i++ {
requests <- i
}
close(requests)
for req := range requests {
<-rateLimiter.C // 等待速率限制器
fmt.Printf(" 处理请求 %d (限速)\n", req)
}
fmt.Println()
}
// ========== 辅助函数和类型定义 ==========
// echoServer 简单的回声服务器
func echoServer(messages <-chan string, responses chan<- string) {
for msg := range messages {
responses <- "Echo: " + msg
}
}
// producer 生产者函数
func producer(id int, items chan<- int, count int, wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < count; i++ {
item := id*100 + i
items <- item
fmt.Printf(" 生产者 %d 生产: %d\n", id, item)
time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond)
}
fmt.Printf(" 生产者 %d 完成\n", id)
}
// consumer 消费者函数
func consumer(id int, items <-chan int, wg *sync.WaitGroup) {
defer wg.Done()
for item := range items {
fmt.Printf(" 消费者 %d 消费: %d\n", id, item)
time.Sleep(time.Duration(rand.Intn(150)) * time.Millisecond)
}
fmt.Printf(" 消费者 %d 完成\n", id)
}
// sender 只发送函数
func sender(ch chan<- int) {
ch <- 42
close(ch)
}
// receiver 只接收函数
func receiver(ch <-chan int) {
value := <-ch
fmt.Printf(" 只接收 channel 接收到: %d\n", value)
}
// generateNumbers 生成数字
func generateNumbers(out chan<- int) {
for i := 1; i <= 5; i++ {
out <- i
}
close(out)
}
// squareNumbers 计算平方
func squareNumbers(in <-chan int, out chan<- int) {
for num := range in {
out <- num * num
}
close(out)
}
// cubeNumbers 计算立方
func cubeNumbers(in <-chan int, out chan<- int) {
for num := range in {
out <- num * num * num
}
close(out)
}
// multipleSender 多发送者函数
func multipleSender(id int, data chan<- int, done <-chan bool) {
for {
select {
case data <- id*10 + rand.Intn(10):
time.Sleep(100 * time.Millisecond)
case <-done:
fmt.Printf(" 发送者 %d 停止\n", id)
return
}
}
}
// fibonacci 斐波那契生成器
func fibonacci(n int) <-chan int {
ch := make(chan int)
go func() {
defer close(ch)
a, b := 0, 1
for i := 0; i < n; i++ {
ch <- a
a, b = b, a+b
}
}()
return ch
}
// sieve 埃拉托斯特尼筛法生成素数
func sieve(max int) <-chan int {
ch := make(chan int)
go func() {
defer close(ch)
isPrime := make([]bool, max+1)
for i := 2; i <= max; i++ {
isPrime[i] = true
}
for i := 2; i*i <= max; i++ {
if isPrime[i] {
for j := i * i; j <= max; j += i {
isPrime[j] = false
}
}
}
for i := 2; i <= max; i++ {
if isPrime[i] {
ch <- i
}
}
}()
return ch
}
// fanOut 扇出函数
func fanOut(input <-chan int, outputs ...chan<- int) {
go func() {
defer func() {
for _, output := range outputs {
close(output)
}
}()
i := 0
for value := range input {
outputs[i%len(outputs)] <- value
i++
}
}()
}
// fanInMultiple 多路扇入函数
func fanInMultiple(inputs ...<-chan string) <-chan string {
output := make(chan string)
var wg sync.WaitGroup
// 为每个输入启动一个 goroutine
for _, input := range inputs {
wg.Add(1)
go func(ch <-chan string) {
defer wg.Done()
for value := range ch {
output <- value
}
}(input)
}
// 等待所有输入完成后关闭输出
go func() {
wg.Wait()
close(output)
}()
return output
}
// WorkJob 工作任务
type WorkJob struct {
ID int
Data string
}
// WorkResult 工作结果
type WorkResult struct {
JobID int
Message string
}
// workPoolWorker 工作池工作者
func workPoolWorker(id int, jobs <-chan WorkJob, results chan<- WorkResult) {
for job := range jobs {
fmt.Printf(" 工作者 %d 开始处理任务 %d\n", id, job.ID)
time.Sleep(time.Duration(rand.Intn(200)) * time.Millisecond)
results <- WorkResult{
JobID: job.ID,
Message: fmt.Sprintf("工作者 %d 完成任务 %d: %s", id, job.ID, job.Data),
}
}
}
/*
运行这个程序:
go run 02-channels.go
学习要点:
1. Channel 是 Go 语言中 goroutine 间通信的主要方式
2. Channel 有无缓冲和有缓冲两种类型
3. Channel 具有方向性,可以限制为只发送或只接收
4. Channel 可以被关闭,关闭后不能再发送数据
5. 使用 range 可以方便地遍历 channel 中的数据
Channel 的特性:
1. 类型安全:只能传递指定类型的数据
2. 同步机制:无缓冲 channel 提供同步语义
3. 异步机制:有缓冲 channel 提供异步语义
4. 方向性:可以限制 channel 的使用方向
5. 可关闭:发送方可以关闭 channel 通知接收方
Channel 类型:
1. 无缓冲 channelmake(chan T)
2. 有缓冲 channelmake(chan T, size)
3. 只发送 channelchan<- T
4. 只接收 channel<-chan T
5. 双向 channelchan T
Channel 操作:
1. 发送ch <- value
2. 接收value := <-ch
3. 接收并检查value, ok := <-ch
4. 关闭close(ch)
5. 遍历for value := range ch
常见模式:
1. 生产者-消费者:使用缓冲 channel 解耦生产和消费
2. 扇出:一个输入分发到多个输出
3. 扇入:多个输入合并到一个输出
4. 管道:链式处理数据
5. 工作池:固定数量的 worker 处理任务
高级用法:
1. 超时控制:使用 time.After
2. 非阻塞操作:使用 select 的 default 分支
3. 心跳机制:使用 time.Ticker
4. 速率限制:控制操作频率
5. 信号通知:使用 channel 作为信号
最佳实践:
1. 发送方负责关闭 channel
2. 不要从接收方关闭 channel
3. 不要关闭已关闭的 channel
4. 使用 range 遍历 channel
5. 使用 select 处理多个 channel
注意事项:
1. 向已关闭的 channel 发送数据会 panic
2. 关闭已关闭的 channel 会 panic
3. 从已关闭的 channel 接收会得到零值
4. nil channel 的发送和接收都会阻塞
5. 无缓冲 channel 的发送和接收必须同时准备好
性能考虑:
1. 无缓冲 channel 有同步开销
2. 有缓冲 channel 可以减少阻塞
3. Channel 操作比直接内存访问慢
4. 合理选择缓冲区大小
5. 避免创建过多的 channel
*/

View File

@@ -0,0 +1,880 @@
/*
03-select.go - Go 语言 Select 语句详解
学习目标:
1. 理解 select 语句的概念和作用
2. 掌握 select 的基本语法和用法
3. 学会使用 select 处理多个 channel
4. 了解 select 的非阻塞操作
5. 掌握 select 的常见应用模式
知识点:
- select 语句的基本语法
- select 的随机选择特性
- default 分支的使用
- select 与超时控制
- select 的常见模式
- select 的最佳实践
*/
package main
import (
"fmt"
"math/rand"
"reflect"
"strings"
"time"
)
func main() {
fmt.Println("=== Go 语言 Select 语句详解 ===\n")
// 演示基本的 select 语句
demonstrateBasicSelect()
// 演示 select 的随机选择
demonstrateRandomSelection()
// 演示 select 的非阻塞操作
demonstrateNonBlockingSelect()
// 演示 select 的超时控制
demonstrateSelectTimeout()
// 演示 select 的常见模式
demonstrateSelectPatterns()
// 演示 select 的高级用法
demonstrateAdvancedSelect()
// 演示 select 的实际应用
demonstratePracticalSelect()
}
// demonstrateBasicSelect 演示基本的 select 语句
func demonstrateBasicSelect() {
fmt.Println("1. 基本的 Select 语句:")
// select 的基本概念
fmt.Printf(" Select 的基本概念:\n")
fmt.Printf(" - 类似于 switch但用于 channel 操作\n")
fmt.Printf(" - 可以同时等待多个 channel 操作\n")
fmt.Printf(" - 随机选择一个可执行的 case\n")
fmt.Printf(" - 如果没有 case 可执行,会阻塞等待\n")
fmt.Printf(" - default 分支提供非阻塞行为\n")
// 基本 select 示例
fmt.Printf(" 基本 select 示例:\n")
ch1 := make(chan string)
ch2 := make(chan string)
// 启动两个 goroutine 发送数据
go func() {
time.Sleep(100 * time.Millisecond)
ch1 <- "来自 channel 1"
}()
go func() {
time.Sleep(200 * time.Millisecond)
ch2 <- "来自 channel 2"
}()
// 使用 select 等待任一 channel
select {
case msg1 := <-ch1:
fmt.Printf(" 接收到: %s\n", msg1)
case msg2 := <-ch2:
fmt.Printf(" 接收到: %s\n", msg2)
}
// 接收剩余的消息
select {
case msg1 := <-ch1:
fmt.Printf(" 接收到: %s\n", msg1)
case msg2 := <-ch2:
fmt.Printf(" 接收到: %s\n", msg2)
}
// 多个 channel 的 select
fmt.Printf(" 多个 channel 的 select:\n")
numbers := make(chan int)
strings := make(chan string)
booleans := make(chan bool)
// 启动发送者
go func() {
numbers <- 42
strings <- "Hello"
booleans <- true
}()
// 接收所有消息
for i := 0; i < 3; i++ {
select {
case num := <-numbers:
fmt.Printf(" 接收到数字: %d\n", num)
case str := <-strings:
fmt.Printf(" 接收到字符串: %s\n", str)
case b := <-booleans:
fmt.Printf(" 接收到布尔值: %t\n", b)
}
}
fmt.Println()
}
// demonstrateRandomSelection 演示 select 的随机选择
func demonstrateRandomSelection() {
fmt.Println("2. Select 的随机选择:")
// 多个 case 同时就绪时的随机选择
fmt.Printf(" 多个 case 同时就绪时的随机选择:\n")
ch1 := make(chan string, 1)
ch2 := make(chan string, 1)
ch3 := make(chan string, 1)
// 预先填充所有 channel
ch1 <- "Channel 1"
ch2 <- "Channel 2"
ch3 <- "Channel 3"
// 多次执行 select观察随机选择
fmt.Printf(" 执行 10 次 select观察随机选择:\n")
for i := 0; i < 10; i++ {
// 重新填充 channel
select {
case <-ch1:
case <-ch2:
case <-ch3:
}
ch1 <- "Channel 1"
ch2 <- "Channel 2"
ch3 <- "Channel 3"
select {
case msg := <-ch1:
fmt.Printf(" 第 %d 次: %s\n", i+1, msg)
case msg := <-ch2:
fmt.Printf(" 第 %d 次: %s\n", i+1, msg)
case msg := <-ch3:
fmt.Printf(" 第 %d 次: %s\n", i+1, msg)
}
}
// 公平调度示例
fmt.Printf(" 公平调度示例:\n")
worker1 := make(chan string, 5)
worker2 := make(chan string, 5)
// 填充任务
for i := 1; i <= 5; i++ {
worker1 <- fmt.Sprintf("Worker1-Task%d", i)
worker2 <- fmt.Sprintf("Worker2-Task%d", i)
}
// 公平地处理两个 worker 的任务
for i := 0; i < 10; i++ {
select {
case task := <-worker1:
fmt.Printf(" 处理: %s\n", task)
case task := <-worker2:
fmt.Printf(" 处理: %s\n", task)
}
}
fmt.Println()
}
// demonstrateNonBlockingSelect 演示 select 的非阻塞操作
func demonstrateNonBlockingSelect() {
fmt.Println("3. Select 的非阻塞操作:")
// 使用 default 分支实现非阻塞
fmt.Printf(" 使用 default 分支实现非阻塞:\n")
ch := make(chan string)
// 非阻塞接收
select {
case msg := <-ch:
fmt.Printf(" 接收到消息: %s\n", msg)
default:
fmt.Printf(" 没有消息可接收\n")
}
// 非阻塞发送
select {
case ch <- "Hello":
fmt.Printf(" 消息发送成功\n")
default:
fmt.Printf(" 消息发送失败channel 未准备好\n")
}
// 非阻塞发送到缓冲 channel
fmt.Printf(" 非阻塞发送到缓冲 channel:\n")
buffered := make(chan int, 2)
// 发送到未满的缓冲 channel
for i := 1; i <= 3; i++ {
select {
case buffered <- i:
fmt.Printf(" 成功发送: %d\n", i)
default:
fmt.Printf(" 发送失败: %d (channel 已满)\n", i)
}
}
// 非阻塞接收
for i := 0; i < 3; i++ {
select {
case value := <-buffered:
fmt.Printf(" 接收到: %d\n", value)
default:
fmt.Printf(" 没有数据可接收\n")
}
}
// 轮询模式
fmt.Printf(" 轮询模式:\n")
status := make(chan string, 1)
// 启动状态更新器
go func() {
statuses := []string{"初始化", "运行中", "暂停", "完成"}
for _, s := range statuses {
time.Sleep(150 * time.Millisecond)
select {
case status <- s:
default:
// 如果 channel 满了,跳过这次更新
}
}
}()
// 轮询状态
for i := 0; i < 10; i++ {
select {
case s := <-status:
fmt.Printf(" 状态更新: %s\n", s)
default:
fmt.Printf(" 状态检查: 无更新\n")
}
time.Sleep(100 * time.Millisecond)
}
fmt.Println()
}
// demonstrateSelectTimeout 演示 select 的超时控制
func demonstrateSelectTimeout() {
fmt.Println("4. Select 的超时控制:")
// 基本超时控制
fmt.Printf(" 基本超时控制:\n")
slowCh := make(chan string)
// 启动一个慢速响应的 goroutine
go func() {
time.Sleep(300 * time.Millisecond)
slowCh <- "慢速响应"
}()
select {
case result := <-slowCh:
fmt.Printf(" 接收到结果: %s\n", result)
case <-time.After(200 * time.Millisecond):
fmt.Printf(" 操作超时\n")
}
// 多级超时控制
fmt.Printf(" 多级超时控制:\n")
fastCh := make(chan string)
mediumCh := make(chan string)
slowCh2 := make(chan string)
// 启动不同速度的响应
go func() {
time.Sleep(50 * time.Millisecond)
fastCh <- "快速响应"
}()
go func() {
time.Sleep(150 * time.Millisecond)
mediumCh <- "中速响应"
}()
go func() {
time.Sleep(350 * time.Millisecond)
slowCh2 <- "慢速响应"
}()
timeout1 := time.After(100 * time.Millisecond)
timeout2 := time.After(200 * time.Millisecond)
timeout3 := time.After(300 * time.Millisecond)
for i := 0; i < 3; i++ {
select {
case result := <-fastCh:
fmt.Printf(" 快速: %s\n", result)
case result := <-mediumCh:
fmt.Printf(" 中速: %s\n", result)
case result := <-slowCh2:
fmt.Printf(" 慢速: %s\n", result)
case <-timeout1:
fmt.Printf(" 第一级超时 (100ms)\n")
timeout1 = nil // 防止重复触发
case <-timeout2:
fmt.Printf(" 第二级超时 (200ms)\n")
timeout2 = nil
case <-timeout3:
fmt.Printf(" 第三级超时 (300ms)\n")
timeout3 = nil
}
}
// 心跳超时检测
fmt.Printf(" 心跳超时检测:\n")
heartbeat := make(chan bool)
// 启动心跳发送器
go func() {
ticker := time.NewTicker(80 * time.Millisecond)
defer ticker.Stop()
for i := 0; i < 5; i++ {
select {
case <-ticker.C:
heartbeat <- true
}
}
}()
// 监控心跳
for i := 0; i < 8; i++ {
select {
case <-heartbeat:
fmt.Printf(" 心跳正常 %d\n", i+1)
case <-time.After(100 * time.Millisecond):
fmt.Printf(" 心跳超时 %d\n", i+1)
}
}
fmt.Println()
}
// demonstrateSelectPatterns 演示 select 的常见模式
func demonstrateSelectPatterns() {
fmt.Println("5. Select 的常见模式:")
// 扇入模式
fmt.Printf(" 扇入模式:\n")
input1 := make(chan int)
input2 := make(chan int)
input3 := make(chan int)
// 启动数据源
go func() {
for i := 1; i <= 3; i++ {
input1 <- i
time.Sleep(100 * time.Millisecond)
}
close(input1)
}()
go func() {
for i := 10; i <= 12; i++ {
input2 <- i
time.Sleep(150 * time.Millisecond)
}
close(input2)
}()
go func() {
for i := 100; i <= 102; i++ {
input3 <- i
time.Sleep(200 * time.Millisecond)
}
close(input3)
}()
// 扇入合并
for {
select {
case val, ok := <-input1:
if ok {
fmt.Printf(" 来源1: %d\n", val)
} else {
input1 = nil
}
case val, ok := <-input2:
if ok {
fmt.Printf(" 来源2: %d\n", val)
} else {
input2 = nil
}
case val, ok := <-input3:
if ok {
fmt.Printf(" 来源3: %d\n", val)
} else {
input3 = nil
}
}
// 所有 channel 都关闭时退出
if input1 == nil && input2 == nil && input3 == nil {
break
}
}
// 优雅关闭模式
fmt.Printf(" 优雅关闭模式:\n")
data := make(chan int)
done := make(chan bool)
// 启动工作 goroutine
go func() {
defer close(data)
for i := 1; i <= 10; i++ {
select {
case data <- i:
fmt.Printf(" 发送数据: %d\n", i)
time.Sleep(50 * time.Millisecond)
case <-done:
fmt.Printf(" 接收到关闭信号,停止发送\n")
return
}
}
}()
// 接收数据,然后发送关闭信号
count := 0
for value := range data {
fmt.Printf(" 接收数据: %d\n", value)
count++
if count >= 5 {
fmt.Printf(" 发送关闭信号\n")
close(done)
}
}
// 多路复用模式
fmt.Printf(" 多路复用模式:\n")
requests := make(chan Request, 5)
responses := make(chan Response, 5)
errors := make(chan error, 5)
// 启动请求处理器
go requestProcessor(requests, responses, errors)
// 发送请求
for i := 1; i <= 5; i++ {
requests <- Request{ID: i, Data: fmt.Sprintf("请求-%d", i)}
}
close(requests)
// 处理响应和错误
for i := 0; i < 5; i++ {
select {
case resp := <-responses:
fmt.Printf(" 响应: ID=%d, Result=%s\n", resp.ID, resp.Result)
case err := <-errors:
fmt.Printf(" 错误: %v\n", err)
}
}
fmt.Println()
}
// demonstrateAdvancedSelect 演示 select 的高级用法
func demonstrateAdvancedSelect() {
fmt.Println("6. Select 的高级用法:")
// 动态 case 选择
fmt.Printf(" 动态 case 选择:\n")
channels := []chan int{
make(chan int, 1),
make(chan int, 1),
make(chan int, 1),
}
// 填充数据
for i, ch := range channels {
ch <- (i + 1) * 10
}
// 动态选择 channel
for i := 0; i < 3; i++ {
selectFromChannels(channels)
}
// 优先级选择
fmt.Printf(" 优先级选择:\n")
highPriority := make(chan string, 2)
lowPriority := make(chan string, 2)
// 填充不同优先级的任务
highPriority <- "高优先级任务1"
lowPriority <- "低优先级任务1"
highPriority <- "高优先级任务2"
lowPriority <- "低优先级任务2"
// 优先处理高优先级任务
for i := 0; i < 4; i++ {
select {
case task := <-highPriority:
fmt.Printf(" 处理: %s\n", task)
default:
select {
case task := <-lowPriority:
fmt.Printf(" 处理: %s\n", task)
default:
fmt.Printf(" 没有任务\n")
}
}
}
// 速率限制
fmt.Printf(" 速率限制:\n")
rateLimiter := time.NewTicker(100 * time.Millisecond)
defer rateLimiter.Stop()
tasks := make(chan string, 5)
for i := 1; i <= 5; i++ {
tasks <- fmt.Sprintf("任务%d", i)
}
close(tasks)
for task := range tasks {
select {
case <-rateLimiter.C:
fmt.Printf(" 执行: %s\n", task)
}
}
// 断路器模式
fmt.Printf(" 断路器模式:\n")
service := make(chan string)
failures := 0
maxFailures := 3
// 模拟服务调用
go func() {
defer close(service)
for i := 1; i <= 6; i++ {
time.Sleep(50 * time.Millisecond)
if rand.Float32() < 0.5 { // 50% 失败率
service <- fmt.Sprintf("成功响应%d", i)
} else {
service <- "ERROR"
}
}
}()
for response := range service {
if response == "ERROR" {
failures++
fmt.Printf(" 服务失败 (%d/%d)\n", failures, maxFailures)
if failures >= maxFailures {
fmt.Printf(" 断路器打开,停止调用服务\n")
break
}
} else {
failures = 0 // 重置失败计数
fmt.Printf(" %s\n", response)
}
}
fmt.Println()
}
// demonstratePracticalSelect 演示 select 的实际应用
func demonstratePracticalSelect() {
fmt.Println("7. Select 的实际应用:")
// Web 服务器超时处理
fmt.Printf(" Web 服务器超时处理:\n")
requests := make(chan WebRequest, 3)
// 模拟 Web 请求
go func() {
requests <- WebRequest{ID: 1, URL: "/api/fast", ProcessTime: 50 * time.Millisecond}
requests <- WebRequest{ID: 2, URL: "/api/slow", ProcessTime: 300 * time.Millisecond}
requests <- WebRequest{ID: 3, URL: "/api/medium", ProcessTime: 150 * time.Millisecond}
close(requests)
}()
for req := range requests {
handleWebRequest(req)
}
// 数据库连接池
fmt.Printf(" 数据库连接池:\n")
connectionPool := make(chan *DBConnection, 2)
// 初始化连接池
for i := 1; i <= 2; i++ {
connectionPool <- &DBConnection{ID: i}
}
// 模拟数据库操作
for i := 1; i <= 5; i++ {
go performDBOperation(i, connectionPool)
}
time.Sleep(500 * time.Millisecond)
// 消息队列处理
fmt.Printf(" 消息队列处理:\n")
messageQueue := make(chan Message, 10)
deadLetterQueue := make(chan Message, 10)
// 启动消息处理器
go messageProcessor(messageQueue, deadLetterQueue)
// 发送消息
messages := []Message{
{ID: 1, Content: "正常消息1", RetryCount: 0},
{ID: 2, Content: "错误消息", RetryCount: 0},
{ID: 3, Content: "正常消息2", RetryCount: 0},
}
for _, msg := range messages {
messageQueue <- msg
}
close(messageQueue)
// 处理死信队列
time.Sleep(200 * time.Millisecond)
close(deadLetterQueue)
fmt.Printf(" 死信队列中的消息:\n")
for deadMsg := range deadLetterQueue {
fmt.Printf(" 死信: ID=%d, Content=%s, Retries=%d\n",
deadMsg.ID, deadMsg.Content, deadMsg.RetryCount)
}
fmt.Println()
}
// ========== 辅助函数和类型定义 ==========
// Request 请求结构
type Request struct {
ID int
Data string
}
// Response 响应结构
type Response struct {
ID int
Result string
}
// requestProcessor 请求处理器
func requestProcessor(requests <-chan Request, responses chan<- Response, errors chan<- error) {
for req := range requests {
// 模拟处理时间
time.Sleep(50 * time.Millisecond)
// 模拟随机错误
if rand.Float32() < 0.2 { // 20% 错误率
errors <- fmt.Errorf("处理请求 %d 失败", req.ID)
} else {
responses <- Response{
ID: req.ID,
Result: fmt.Sprintf("处理完成: %s", req.Data),
}
}
}
close(responses)
close(errors)
}
// selectFromChannels 动态选择 channel
func selectFromChannels(channels []chan int) {
// 构建 select cases
cases := make([]reflect.SelectCase, len(channels))
for i, ch := range channels {
cases[i] = reflect.SelectCase{
Dir: reflect.SelectRecv,
Chan: reflect.ValueOf(ch),
}
}
// 执行 select
chosen, value, ok := reflect.Select(cases)
if ok {
fmt.Printf(" 从 channel %d 接收到: %d\n", chosen, value.Int())
} else {
fmt.Printf(" channel %d 已关闭\n", chosen)
}
}
// WebRequest Web 请求结构
type WebRequest struct {
ID int
URL string
ProcessTime time.Duration
}
// handleWebRequest 处理 Web 请求
func handleWebRequest(req WebRequest) {
fmt.Printf(" 处理请求 %d: %s\n", req.ID, req.URL)
result := make(chan string)
// 启动请求处理
go func() {
time.Sleep(req.ProcessTime)
result <- fmt.Sprintf("请求 %d 处理完成", req.ID)
}()
// 设置超时
select {
case response := <-result:
fmt.Printf(" %s\n", response)
case <-time.After(200 * time.Millisecond):
fmt.Printf(" 请求 %d 超时\n", req.ID)
}
}
// DBConnection 数据库连接
type DBConnection struct {
ID int
}
// performDBOperation 执行数据库操作
func performDBOperation(operationID int, pool chan *DBConnection) {
select {
case conn := <-pool:
fmt.Printf(" 操作 %d 获取连接 %d\n", operationID, conn.ID)
// 模拟数据库操作
time.Sleep(100 * time.Millisecond)
fmt.Printf(" 操作 %d 完成,释放连接 %d\n", operationID, conn.ID)
pool <- conn
case <-time.After(50 * time.Millisecond):
fmt.Printf(" 操作 %d 获取连接超时\n", operationID)
}
}
// Message 消息结构
type Message struct {
ID int
Content string
RetryCount int
}
// messageProcessor 消息处理器
func messageProcessor(messages <-chan Message, deadLetter chan<- Message) {
for msg := range messages {
fmt.Printf(" 处理消息 %d: %s\n", msg.ID, msg.Content)
// 模拟处理
success := !strings.Contains(msg.Content, "错误")
if success {
fmt.Printf(" 消息 %d 处理成功\n", msg.ID)
} else {
msg.RetryCount++
if msg.RetryCount < 3 {
fmt.Printf(" 消息 %d 处理失败,重试 %d\n", msg.ID, msg.RetryCount)
// 在实际应用中,这里会重新放入队列
} else {
fmt.Printf(" 消息 %d 重试次数超限,放入死信队列\n", msg.ID)
deadLetter <- msg
}
}
}
}
/*
运行这个程序:
go run 03-select.go
学习要点:
1. Select 语句用于处理多个 channel 操作
2. Select 会随机选择一个可执行的 case
3. Default 分支提供非阻塞行为
4. Select 常用于超时控制和多路复用
5. Select 是实现复杂并发模式的重要工具
Select 的特性:
1. 多路选择:可以同时等待多个 channel 操作
2. 随机选择:当多个 case 同时就绪时随机选择
3. 阻塞行为:没有 case 就绪时会阻塞等待
4. 非阻塞default 分支提供非阻塞行为
5. 公平调度:避免某个 channel 被饿死
Select 语法:
1. 基本语法select { case <-ch: ... }
2. 接收操作case value := <-ch:
3. 发送操作case ch <- value:
4. 默认分支default:
5. 超时控制case <-time.After(duration):
常见模式:
1. 超时控制:使用 time.After 设置超时
2. 非阻塞操作:使用 default 分支
3. 扇入合并:合并多个输入源
4. 优雅关闭:使用 done channel 通知退出
5. 多路复用:同时处理多种类型的消息
高级用法:
1. 动态 case使用 reflect.Select 动态构建 case
2. 优先级选择:嵌套 select 实现优先级
3. 速率限制:结合 time.Ticker 控制频率
4. 断路器:实现服务降级和熔断
5. 负载均衡:在多个服务间分发请求
实际应用:
1. Web 服务器:请求超时处理
2. 数据库:连接池管理
3. 消息队列:消息路由和处理
4. 微服务:服务间通信
5. 监控系统:多源数据收集
最佳实践:
1. 避免在 select 中执行耗时操作
2. 合理设置超时时间
3. 正确处理 channel 关闭
4. 使用 default 避免死锁
5. 注意 select 的随机性
性能考虑:
1. Select 的开销比单个 channel 操作大
2. Case 数量影响性能
3. 随机选择有一定开销
4. 合理使用缓冲 channel
5. 避免过度复杂的 select 结构
注意事项:
1. Select 中的 case 必须是 channel 操作
2. nil channel 的 case 永远不会被选中
3. 关闭的 channel 可以被选中
4. Default 分支不能与其他阻塞操作共存
5. Select 语句本身不是循环
*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,957 @@
/*
01-basic-errors.go - Go 语言基础错误处理详解
学习目标:
1. 理解 Go 语言的错误处理哲学
2. 掌握 error 接口的使用
3. 学会基本的错误处理模式
4. 了解错误传播和包装
5. 掌握错误处理的最佳实践
知识点:
- error 接口的定义和实现
- 错误的创建和返回
- 错误检查和处理
- 错误传播和包装
- 错误处理的惯用法
- 错误信息的设计
*/
package main
import (
"crypto/rand"
"encoding/json"
"errors"
"fmt"
"os"
"strings"
"sync"
"time"
)
func main() {
fmt.Println("=== Go 语言基础错误处理详解 ===\\n")
// 演示错误接口的基本概念
demonstrateErrorInterface()
// 演示错误的创建方式
demonstrateErrorCreation()
// 演示错误检查和处理
demonstrateErrorHandling()
// 演示错误传播
demonstrateErrorPropagation()
// 演示错误包装
demonstrateErrorWrapping()
// 演示错误处理模式
demonstrateErrorPatterns()
// 演示实际应用场景
demonstratePracticalExamples()
}
// demonstrateErrorInterface 演示错误接口的基本概念
func demonstrateErrorInterface() {
fmt.Println("1. 错误接口的基本概念:")
// error 接口的定义
fmt.Printf(" error 接口的定义:\\n")
fmt.Printf(" type error interface {\\n")
fmt.Printf(" Error() string\\n")
fmt.Printf(" }\\n")
fmt.Printf("\\n")
fmt.Printf(" 错误处理的特点:\\n")
fmt.Printf(" - 错误是值,可以像其他值一样传递\\n")
fmt.Printf(" - 使用多返回值模式处理错误\\n")
fmt.Printf(" - 显式错误检查,不隐藏错误\\n")
fmt.Printf(" - 错误应该被处理,不应该被忽略\\n")
fmt.Printf(" - 错误信息应该清晰、有用\\n")
// 基本错误示例
fmt.Printf(" 基本错误示例:\\n")
// 成功的情况
result, err := divide(10, 2)
if err != nil {
fmt.Printf(" 错误: %v\\n", err)
} else {
fmt.Printf(" 10 / 2 = %.2f\\n", result)
}
// 错误的情况
result, err = divide(10, 0)
if err != nil {
fmt.Printf(" 错误: %v\\n", err)
} else {
fmt.Printf(" 10 / 0 = %.2f\\n", result)
}
// nil 错误检查
fmt.Printf(" nil 错误检查:\\n")
var nilError error
fmt.Printf(" nil 错误: %v\\n", nilError)
fmt.Printf(" nil 错误 == nil: %t\\n", nilError == nil)
// 错误比较
fmt.Printf(" 错误比较:\\n")
err1 := errors.New("相同的错误")
err2 := errors.New("相同的错误")
fmt.Printf(" err1 == err2: %t (内容相同但不是同一个对象)\\n", err1 == err2)
fmt.Printf(" err1.Error() == err2.Error(): %t\\n", err1.Error() == err2.Error())
fmt.Println()
}
// demonstrateErrorCreation 演示错误的创建方式
func demonstrateErrorCreation() {
fmt.Println("2. 错误的创建方式:")
// 使用 errors.New 创建错误
fmt.Printf(" 使用 errors.New 创建错误:\\n")
err1 := errors.New("这是一个简单的错误")
fmt.Printf(" 错误1: %v\\n", err1)
// 使用 fmt.Errorf 创建格式化错误
fmt.Printf(" 使用 fmt.Errorf 创建格式化错误:\\n")
username := "alice"
err2 := fmt.Errorf("用户 %s 不存在", username)
fmt.Printf(" 错误2: %v\\n", err2)
// 创建带有更多信息的错误
age := -5
err3 := fmt.Errorf("无效的年龄值: %d (年龄必须大于0)", age)
fmt.Printf(" 错误3: %v\\n", err3)
// 使用预定义错误
fmt.Printf(" 使用预定义错误:\\n")
predefinedErrors := []error{
ErrInvalidInput,
ErrNotFound,
ErrPermissionDenied,
ErrTimeout,
}
for i, err := range predefinedErrors {
fmt.Printf(" 预定义错误%d: %v\\n", i+1, err)
}
// 条件性错误创建
fmt.Printf(" 条件性错误创建:\\n")
testValues := []int{-1, 0, 5, 101}
for _, value := range testValues {
if err := validateAge(value); err != nil {
fmt.Printf(" 验证年龄 %d: %v\\n", value, err)
} else {
fmt.Printf(" 验证年龄 %d: 有效\\n", value)
}
}
fmt.Println()
}
// demonstrateErrorHandling 演示错误检查和处理
func demonstrateErrorHandling() {
fmt.Println("3. 错误检查和处理:")
// 基本错误检查模式
fmt.Printf(" 基本错误检查模式:\\n")
// 立即检查错误
content, err := readFile("example.txt")
if err != nil {
fmt.Printf(" 读取文件失败: %v\\n", err)
} else {
fmt.Printf(" 文件内容: %s\\n", content)
}
// 多个操作的错误处理
fmt.Printf(" 多个操作的错误处理:\\n")
err = performMultipleOperations()
if err != nil {
fmt.Printf(" 多个操作失败: %v\\n", err)
} else {
fmt.Printf(" 所有操作成功完成\\n")
}
// 错误类型检查
fmt.Printf(" 错误类型检查:\\n")
testOperations := []func() error{
func() error { return ErrNotFound },
func() error { return ErrPermissionDenied },
func() error { return fmt.Errorf("未知错误") },
func() error { return nil },
}
for i, op := range testOperations {
err := op()
fmt.Printf(" 操作%d: ", i+1)
handleSpecificError(err)
}
// 错误恢复
fmt.Printf(" 错误恢复:\\n")
data, err := fetchDataWithRetry("https://api.example.com/data", 3)
if err != nil {
fmt.Printf(" 获取数据失败: %v\\n", err)
} else {
fmt.Printf(" 获取数据成功: %s\\n", data)
}
// 部分失败处理
fmt.Printf(" 部分失败处理:\\n")
results, errors := processBatch([]string{"item1", "item2", "invalid", "item4"})
fmt.Printf(" 成功处理: %v\\n", results)
fmt.Printf(" 处理错误: %v\\n", errors)
fmt.Println()
}
// demonstrateErrorPropagation 演示错误传播
func demonstrateErrorPropagation() {
fmt.Println("4. 错误传播:")
// 简单错误传播
fmt.Printf(" 简单错误传播:\\n")
result, err := calculateTotal([]float64{10.5, 20.0, -5.0, 15.5})
if err != nil {
fmt.Printf(" 计算总和失败: %v\\n", err)
} else {
fmt.Printf(" 总和: %.2f\\n", result)
}
// 带上下文的错误传播
fmt.Printf(" 带上下文的错误传播:\\n")
user, err := getUserProfile("nonexistent_user")
if err != nil {
fmt.Printf(" 获取用户资料失败: %v\\n", err)
} else {
fmt.Printf(" 用户资料: %+v\\n", user)
}
// 错误链
fmt.Printf(" 错误链:\\n")
err = processOrder("invalid_order_id")
if err != nil {
fmt.Printf(" 处理订单失败: %v\\n", err)
// 展示错误链
fmt.Printf(" 错误链分析:\\n")
printErrorChain(err, " ")
}
// 选择性错误传播
fmt.Printf(" 选择性错误传播:\\n")
results := []string{}
errors := []error{}
items := []string{"valid1", "invalid", "valid2", "error", "valid3"}
for _, item := range items {
result, err := processItem(item)
if err != nil {
errors = append(errors, fmt.Errorf("处理 %s 失败: %w", item, err))
} else {
results = append(results, result)
}
}
fmt.Printf(" 成功结果: %v\\n", results)
if len(errors) > 0 {
fmt.Printf(" 错误列表:\\n")
for _, err := range errors {
fmt.Printf(" - %v\\n", err)
}
}
fmt.Println()
}
// demonstrateErrorWrapping 演示错误包装
func demonstrateErrorWrapping() {
fmt.Println("5. 错误包装:")
// 基本错误包装
fmt.Printf(" 基本错误包装:\\n")
originalErr := errors.New("原始错误")
wrappedErr := fmt.Errorf("包装错误: %w", originalErr)
fmt.Printf(" 原始错误: %v\\n", originalErr)
fmt.Printf(" 包装错误: %v\\n", wrappedErr)
// 错误解包
fmt.Printf(" 错误解包:\\n")
unwrappedErr := errors.Unwrap(wrappedErr)
fmt.Printf(" 解包后的错误: %v\\n", unwrappedErr)
fmt.Printf(" 解包后是否为原始错误: %t\\n", unwrappedErr == originalErr)
// 错误检查 (errors.Is)
fmt.Printf(" 错误检查 (errors.Is):\\n")
fmt.Printf(" wrappedErr 是否为 originalErr: %t\\n", errors.Is(wrappedErr, originalErr))
fmt.Printf(" wrappedErr 是否为 ErrNotFound: %t\\n", errors.Is(wrappedErr, ErrNotFound))
// 多层包装
fmt.Printf(" 多层包装:\\n")
baseErr := ErrNotFound
level1Err := fmt.Errorf("数据库查询失败: %w", baseErr)
level2Err := fmt.Errorf("用户服务错误: %w", level1Err)
level3Err := fmt.Errorf("API 请求失败: %w", level2Err)
fmt.Printf(" 多层包装错误: %v\\n", level3Err)
fmt.Printf(" 是否包含 ErrNotFound: %t\\n", errors.Is(level3Err, ErrNotFound))
// 错误类型断言 (errors.As)
fmt.Printf(" 错误类型断言 (errors.As):\\n")
customErr := &CustomError{
Code: 404,
Message: "资源未找到",
Details: "请求的用户ID不存在",
}
wrappedCustomErr := fmt.Errorf("处理请求失败: %w", customErr)
var targetErr *CustomError
if errors.As(wrappedCustomErr, &targetErr) {
fmt.Printf(" 找到自定义错误: Code=%d, Message=%s\\n",
targetErr.Code, targetErr.Message)
}
fmt.Println()
}
// demonstrateErrorPatterns 演示错误处理模式
func demonstrateErrorPatterns() {
fmt.Println("6. 错误处理模式:")
// 哨兵错误模式
fmt.Printf(" 哨兵错误模式:\\n")
_, err := findUser("nonexistent")
if errors.Is(err, ErrUserNotFound) {
fmt.Printf(" 用户不存在,使用默认用户\\n")
} else if err != nil {
fmt.Printf(" 查找用户时发生其他错误: %v\\n", err)
}
// 错误类型模式
fmt.Printf(" 错误类型模式:\\n")
err = performNetworkOperation()
var netErr *NetworkError
if errors.As(err, &netErr) {
if netErr.Temporary {
fmt.Printf(" 临时网络错误,可以重试: %v\\n", netErr)
} else {
fmt.Printf(" 永久网络错误: %v\\n", netErr)
}
}
// 不透明错误模式
fmt.Printf(" 不透明错误模式:\\n")
err = callExternalAPI()
if err != nil {
fmt.Printf(" 外部API调用失败: %v\\n", err)
// 不检查具体错误类型,统一处理
}
// 错误聚合模式
fmt.Printf(" 错误聚合模式:\\n")
validator := NewValidator()
validator.ValidateRequired("name", "")
validator.ValidateEmail("email", "invalid-email")
validator.ValidateRange("age", -5, 0, 120)
if validator.HasErrors() {
fmt.Printf(" 验证失败:\\n")
for _, err := range validator.Errors() {
fmt.Printf(" - %v\\n", err)
}
}
// 错误恢复模式
fmt.Printf(" 错误恢复模式:\\n")
result := performWithFallback()
fmt.Printf(" 操作结果: %s\\n", result)
// 错误重试模式
fmt.Printf(" 错误重试模式:\\n")
data, err := retryOperation(func() (string, error) {
// 模拟不稳定的操作
if len(fmt.Sprintf("%d", rand.Int()))%3 == 0 {
return "成功数据", nil
}
return "", errors.New("临时失败")
}, 3)
if err != nil {
fmt.Printf(" 重试操作最终失败: %v\\n", err)
} else {
fmt.Printf(" 重试操作成功: %s\\n", data)
}
fmt.Println()
}
// demonstratePracticalExamples 演示实际应用场景
func demonstratePracticalExamples() {
fmt.Println("7. 实际应用场景:")
// 文件操作错误处理
fmt.Printf(" 文件操作错误处理:\\n")
content, err := safeReadFile("config.json")
if err != nil {
fmt.Printf(" 读取配置文件失败: %v\\n", err)
} else {
fmt.Printf(" 配置内容: %s\\n", content)
}
// 网络请求错误处理
fmt.Printf(" 网络请求错误处理:\\n")
response, err := httpGet("https://api.example.com/users/1")
if err != nil {
fmt.Printf(" HTTP请求失败: %v\\n", err)
} else {
fmt.Printf(" HTTP响应: %s\\n", response)
}
// 数据库操作错误处理
fmt.Printf(" 数据库操作错误处理:\\n")
user := User{ID: 1, Name: "Alice", Email: "alice@example.com"}
err = saveUser(user)
if err != nil {
fmt.Printf(" 保存用户失败: %v\\n", err)
} else {
fmt.Printf(" 用户保存成功\\n")
}
// JSON 解析错误处理
fmt.Printf(" JSON 解析错误处理:\\n")
jsonData := `{"name": "Bob", "age": "invalid"}`
user, err = parseUser(jsonData)
if err != nil {
fmt.Printf(" JSON解析失败: %v\\n", err)
} else {
fmt.Printf(" 解析用户: %+v\\n", user)
}
// 业务逻辑错误处理
fmt.Printf(" 业务逻辑错误处理:\\n")
account := BankAccount{Balance: 100.0}
err = account.Withdraw(150.0)
if err != nil {
fmt.Printf(" 取款失败: %v\\n", err)
} else {
fmt.Printf(" 取款成功,余额: %.2f\\n", account.Balance)
}
// 并发错误处理
fmt.Printf(" 并发错误处理:\\n")
results, errors := processConcurrently([]string{"task1", "task2", "error_task", "task4"})
fmt.Printf(" 并发处理结果: %v\\n", results)
if len(errors) > 0 {
fmt.Printf(" 并发处理错误:\\n")
for i, err := range errors {
if err != nil {
fmt.Printf(" 任务%d错误: %v\\n", i, err)
}
}
}
fmt.Println()
}
// ========== 类型定义和辅助函数 ==========
// 预定义错误
var (
ErrInvalidInput = errors.New("输入无效")
ErrNotFound = errors.New("未找到")
ErrPermissionDenied = errors.New("权限被拒绝")
ErrTimeout = errors.New("操作超时")
ErrUserNotFound = errors.New("用户未找到")
)
// CustomError 自定义错误类型
type CustomError struct {
Code int
Message string
Details string
}
func (e *CustomError) Error() string {
return fmt.Sprintf("错误 %d: %s (%s)", e.Code, e.Message, e.Details)
}
// NetworkError 网络错误类型
type NetworkError struct {
Op string
URL string
Temporary bool
Err error
}
func (e *NetworkError) Error() string {
return fmt.Sprintf("网络错误 %s %s: %v", e.Op, e.URL, e.Err)
}
// User 用户结构
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Age int `json:"age"`
}
// BankAccount 银行账户
type BankAccount struct {
Balance float64
}
func (ba *BankAccount) Withdraw(amount float64) error {
if amount <= 0 {
return fmt.Errorf("取款金额必须大于0实际: %.2f", amount)
}
if amount > ba.Balance {
return fmt.Errorf("余额不足: 需要 %.2f,可用 %.2f", amount, ba.Balance)
}
ba.Balance -= amount
return nil
}
// Validator 验证器
type Validator struct {
errors []error
}
func NewValidator() *Validator {
return &Validator{errors: make([]error, 0)}
}
func (v *Validator) ValidateRequired(field, value string) {
if value == "" {
v.errors = append(v.errors, fmt.Errorf("字段 %s 是必需的", field))
}
}
func (v *Validator) ValidateEmail(field, value string) {
if value != "" && !strings.Contains(value, "@") {
v.errors = append(v.errors, fmt.Errorf("字段 %s 不是有效的邮箱地址", field))
}
}
func (v *Validator) ValidateRange(field string, value, min, max int) {
if value < min || value > max {
v.errors = append(v.errors, fmt.Errorf("字段 %s 必须在 %d 到 %d 之间,实际: %d", field, min, max, value))
}
}
func (v *Validator) HasErrors() bool {
return len(v.errors) > 0
}
func (v *Validator) Errors() []error {
return v.errors
}
// ========== 辅助函数 ==========
// divide 除法运算
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("除数不能为零")
}
return a / b, nil
}
// validateAge 验证年龄
func validateAge(age int) error {
if age < 0 {
return fmt.Errorf("年龄不能为负数: %d", age)
}
if age > 150 {
return fmt.Errorf("年龄不能超过150: %d", age)
}
return nil
}
// readFile 读取文件
func readFile(filename string) (string, error) {
// 模拟文件读取
if filename == "example.txt" {
return "", fmt.Errorf("文件 %s 不存在", filename)
}
return "文件内容", nil
}
// performMultipleOperations 执行多个操作
func performMultipleOperations() error {
// 模拟多个操作
operations := []func() error{
func() error { return nil }, // 成功
func() error { return nil }, // 成功
func() error { return errors.New("第三个操作失败") }, // 失败
}
for i, op := range operations {
if err := op(); err != nil {
return fmt.Errorf("操作 %d 失败: %w", i+1, err)
}
}
return nil
}
// handleSpecificError 处理特定错误
func handleSpecificError(err error) {
if err == nil {
fmt.Printf("成功\\n")
return
}
switch {
case errors.Is(err, ErrNotFound):
fmt.Printf("资源未找到\\n")
case errors.Is(err, ErrPermissionDenied):
fmt.Printf("权限不足\\n")
default:
fmt.Printf("未知错误: %v\\n", err)
}
}
// fetchDataWithRetry 带重试的数据获取
func fetchDataWithRetry(url string, maxRetries int) (string, error) {
var lastErr error
for i := 0; i < maxRetries; i++ {
// 模拟网络请求
if rand.Float32() < 0.3 { // 30% 成功率
return fmt.Sprintf("数据来自 %s", url), nil
}
lastErr = fmt.Errorf("请求 %s 失败 (尝试 %d/%d)", url, i+1, maxRetries)
time.Sleep(100 * time.Millisecond) // 重试延迟
}
return "", fmt.Errorf("重试 %d 次后仍然失败: %w", maxRetries, lastErr)
}
// processBatch 批量处理
func processBatch(items []string) ([]string, []error) {
var results []string
var errors []error
for _, item := range items {
if item == "invalid" {
errors = append(errors, fmt.Errorf("无效项目: %s", item))
} else {
results = append(results, fmt.Sprintf("处理后的%s", item))
}
}
return results, errors
}
// calculateTotal 计算总和
func calculateTotal(values []float64) (float64, error) {
total := 0.0
for i, value := range values {
if value < 0 {
return 0, fmt.Errorf("索引 %d 的值不能为负数: %.2f", i, value)
}
total += value
}
return total, nil
}
// getUserProfile 获取用户资料
func getUserProfile(username string) (*User, error) {
// 模拟数据库查询
if username == "nonexistent_user" {
return nil, fmt.Errorf("获取用户资料失败: %w", ErrUserNotFound)
}
return &User{
ID: 1,
Name: username,
Email: username + "@example.com",
}, nil
}
// processOrder 处理订单
func processOrder(orderID string) error {
// 模拟订单处理链
if err := validateOrder(orderID); err != nil {
return fmt.Errorf("处理订单 %s 失败: %w", orderID, err)
}
return nil
}
// validateOrder 验证订单
func validateOrder(orderID string) error {
if orderID == "invalid_order_id" {
if err := checkOrderExists(orderID); err != nil {
return fmt.Errorf("订单验证失败: %w", err)
}
}
return nil
}
// checkOrderExists 检查订单是否存在
func checkOrderExists(orderID string) error {
return fmt.Errorf("数据库查询失败: %w", ErrNotFound)
}
// printErrorChain 打印错误链
func printErrorChain(err error, indent string) {
if err == nil {
return
}
fmt.Printf("%s- %v\\n", indent, err)
if unwrapped := errors.Unwrap(err); unwrapped != nil {
printErrorChain(unwrapped, indent+" ")
}
}
// processItem 处理项目
func processItem(item string) (string, error) {
switch item {
case "invalid":
return "", ErrInvalidInput
case "error":
return "", errors.New("处理错误")
default:
return fmt.Sprintf("处理后的%s", item), nil
}
}
// findUser 查找用户
func findUser(username string) (*User, error) {
if username == "nonexistent" {
return nil, ErrUserNotFound
}
return &User{Name: username}, nil
}
// performNetworkOperation 执行网络操作
func performNetworkOperation() error {
return &NetworkError{
Op: "GET",
URL: "https://api.example.com",
Temporary: true,
Err: errors.New("连接超时"),
}
}
// callExternalAPI 调用外部API
func callExternalAPI() error {
return errors.New("外部服务不可用")
}
// performWithFallback 带回退的操作
func performWithFallback() string {
// 尝试主要操作
if err := primaryOperation(); err != nil {
// 主要操作失败,使用回退
return fallbackOperation()
}
return "主要操作成功"
}
// primaryOperation 主要操作
func primaryOperation() error {
return errors.New("主要操作失败")
}
// fallbackOperation 回退操作
func fallbackOperation() string {
return "回退操作成功"
}
// retryOperation 重试操作
func retryOperation(op func() (string, error), maxRetries int) (string, error) {
var lastErr error
for i := 0; i < maxRetries; i++ {
result, err := op()
if err == nil {
return result, nil
}
lastErr = err
fmt.Printf(" 尝试 %d/%d 失败: %v\\n", i+1, maxRetries, err)
if i < maxRetries-1 {
time.Sleep(100 * time.Millisecond)
}
}
return "", fmt.Errorf("重试 %d 次后失败: %w", maxRetries, lastErr)
}
// safeReadFile 安全读取文件
func safeReadFile(filename string) (string, error) {
// 模拟文件读取
switch filename {
case "config.json":
return "", fmt.Errorf("读取文件 %s 失败: %w", filename, os.ErrNotExist)
default:
return "文件内容", nil
}
}
// httpGet HTTP GET 请求
func httpGet(url string) (string, error) {
// 模拟HTTP请求
if strings.Contains(url, "example.com") {
return "", &NetworkError{
Op: "GET",
URL: url,
Temporary: false,
Err: errors.New("域名解析失败"),
}
}
return "HTTP响应内容", nil
}
// saveUser 保存用户
func saveUser(user User) error {
// 模拟数据库保存
if user.Email == "" {
return fmt.Errorf("保存用户失败: %w", ErrInvalidInput)
}
return nil
}
// parseUser 解析用户JSON
func parseUser(jsonData string) (User, error) {
var user User
if err := json.Unmarshal([]byte(jsonData), &user); err != nil {
return User{}, fmt.Errorf("解析用户JSON失败: %w", err)
}
return user, nil
}
// processConcurrently 并发处理
func processConcurrently(tasks []string) ([]string, []error) {
var wg sync.WaitGroup
results := make([]string, len(tasks))
errors := make([]error, len(tasks))
for i, task := range tasks {
wg.Add(1)
go func(index int, taskName string) {
defer wg.Done()
// 模拟任务处理
if strings.Contains(taskName, "error") {
errors[index] = fmt.Errorf("任务 %s 处理失败", taskName)
} else {
results[index] = fmt.Sprintf("处理后的%s", taskName)
}
}(i, task)
}
wg.Wait()
return results, errors
}
/*
运行这个程序:
go run 01-basic-errors.go
学习要点:
1. Go 语言使用显式错误处理,错误是值
2. error 接口只有一个 Error() string 方法
3. 使用多返回值模式处理错误
4. 错误应该被检查和处理,不应该被忽略
5. 错误信息应该清晰、有用、包含上下文
错误处理的特点:
1. 显式性:错误必须被显式检查
2. 简单性error 接口设计简单
3. 组合性:错误可以被包装和组合
4. 传播性:错误可以在调用栈中传播
5. 灵活性:支持多种错误处理模式
错误创建方式:
1. errors.New():创建简单错误
2. fmt.Errorf():创建格式化错误
3. 自定义错误类型:实现 error 接口
4. 预定义错误:定义常用错误变量
5. 错误包装:使用 %w 动词包装错误
错误检查模式:
1. 立即检查if err != nil { ... }
2. 错误传播return err 或 return fmt.Errorf("...: %w", err)
3. 错误类型检查errors.Is() 和 errors.As()
4. 错误恢复:提供默认值或回退方案
5. 错误聚合:收集多个错误
错误处理模式:
1. 哨兵错误:预定义的错误值
2. 错误类型:自定义错误结构体
3. 不透明错误:不检查具体错误类型
4. 错误包装:添加上下文信息
5. 错误聚合:收集和批量处理错误
最佳实践:
1. 错误信息应该小写开头,不以标点结尾
2. 错误信息应该包含足够的上下文
3. 使用错误包装传播上下文
4. 不要忽略错误,至少要记录日志
5. 在适当的层级处理错误
常见陷阱:
1. 忽略错误返回值
2. 错误信息不够清晰
3. 过度包装错误
4. 不适当的错误类型检查
5. 在错误处理中引入新的错误
性能考虑:
1. 错误创建有一定开销
2. 错误包装会增加内存使用
3. 错误检查是必要的开销
4. 避免在热点路径创建复杂错误
5. 合理使用预定义错误
注意事项:
1. nil 错误表示没有错误
2. 错误比较使用 == 或 errors.Is()
3. 错误类型断言使用 errors.As()
4. 错误包装使用 fmt.Errorf() 和 %w
5. 错误解包使用 errors.Unwrap()
*/

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,941 @@
/*
03-panic-recover.go - Go 语言 Panic 和 Recover 详解
学习目标:
1. 理解 panic 的概念和使用场景
2. 掌握 recover 的恢复机制
3. 学会 defer 与 panic/recover 的配合
4. 了解 panic 的传播机制
5. 掌握 panic/recover 的最佳实践
知识点:
- panic 的触发条件和行为
- recover 的恢复机制
- defer 语句的执行顺序
- panic 的传播和栈展开
- panic/recover 的实际应用
- 错误处理 vs panic 的选择
*/
package main
import (
"fmt"
"runtime"
"strconv"
"time"
)
func main() {
fmt.Println("=== Go 语言 Panic 和 Recover 详解 ===\\n")
// 演示 panic 的基本概念
demonstratePanicBasics()
// 演示 recover 的使用
demonstrateRecover()
// 演示 defer 与 panic/recover 的配合
demonstrateDeferWithPanicRecover()
// 演示 panic 的传播
demonstratePanicPropagation()
// 演示 panic/recover 的实际应用
demonstratePracticalUsage()
// 演示最佳实践
demonstrateBestPractices()
// 演示错误处理 vs panic 的选择
demonstrateErrorVsPanic()
}
// demonstratePanicBasics 演示 panic 的基本概念
func demonstratePanicBasics() {
fmt.Println("1. Panic 的基本概念:")
// panic 的基本特性
fmt.Printf(" Panic 的基本特性:\\n")
fmt.Printf(" - panic 是运行时错误,会导致程序崩溃\\n")
fmt.Printf(" - panic 会停止当前函数的执行\\n")
fmt.Printf(" - panic 会执行当前函数的 defer 语句\\n")
fmt.Printf(" - panic 会向上传播到调用栈\\n")
fmt.Printf(" - panic 可以被 recover 捕获\\n")
// 手动触发 panic
fmt.Printf(" 手动触发 panic:\\n")
func() {
defer func() {
if r := recover(); r != nil {
fmt.Printf(" 捕获到 panic: %v\\n", r)
}
}()
fmt.Printf(" 准备触发 panic\\n")
panic("这是一个手动触发的 panic")
fmt.Printf(" 这行代码不会执行\\n")
}()
// 常见的 panic 场景
fmt.Printf(" 常见的 panic 场景:\\n")
// 1. 数组越界
func() {
defer func() {
if r := recover(); r != nil {
fmt.Printf(" 数组越界 panic: %v\\n", r)
}
}()
arr := [3]int{1, 2, 3}
fmt.Printf(" 访问数组索引 5: %d\\n", arr[5]) // 会 panic
}()
// 2. 空指针解引用
func() {
defer func() {
if r := recover(); r != nil {
fmt.Printf(" 空指针解引用 panic: %v\\n", r)
}
}()
var ptr *int
fmt.Printf(" 解引用空指针: %d\\n", *ptr) // 会 panic
}()
// 3. 类型断言失败
func() {
defer func() {
if r := recover(); r != nil {
fmt.Printf(" 类型断言失败 panic: %v\\n", r)
}
}()
var x interface{} = "hello"
num := x.(int) // 会 panic
fmt.Printf(" 类型断言结果: %d\\n", num)
}()
// 4. 向已关闭的 channel 发送数据
func() {
defer func() {
if r := recover(); r != nil {
fmt.Printf(" 向已关闭 channel 发送数据 panic: %v\\n", r)
}
}()
ch := make(chan int)
close(ch)
ch <- 1 // 会 panic
}()
fmt.Println()
}
// demonstrateRecover 演示 recover 的使用
func demonstrateRecover() {
fmt.Println("2. Recover 的使用:")
// recover 的基本概念
fmt.Printf(" Recover 的基本概念:\\n")
fmt.Printf(" - recover 只能在 defer 函数中使用\\n")
fmt.Printf(" - recover 可以捕获当前 goroutine 的 panic\\n")
fmt.Printf(" - recover 返回 panic 的值\\n")
fmt.Printf(" - recover 后程序可以继续执行\\n")
// 基本 recover 示例
fmt.Printf(" 基本 recover 示例:\\n")
result := safeFunction(func() int {
panic("计算过程中发生错误")
return 42
})
fmt.Printf(" 安全函数返回: %d\\n", result)
// recover 的返回值
fmt.Printf(" recover 的返回值:\\n")
func() {
defer func() {
if r := recover(); r != nil {
fmt.Printf(" panic 值: %v\\n", r)
fmt.Printf(" panic 类型: %T\\n", r)
// 根据 panic 类型进行不同处理
switch v := r.(type) {
case string:
fmt.Printf(" 字符串 panic: %s\\n", v)
case int:
fmt.Printf(" 整数 panic: %d\\n", v)
case error:
fmt.Printf(" 错误 panic: %v\\n", v)
default:
fmt.Printf(" 其他类型 panic: %v\\n", v)
}
}
}()
// 触发不同类型的 panic
testPanics := []interface{}{
"字符串错误",
42,
fmt.Errorf("错误对象"),
struct{ Message string }{"结构体错误"},
}
for i, panicValue := range testPanics {
func() {
defer func() {
if r := recover(); r != nil {
fmt.Printf(" 测试 %d - panic: %v (%T)\\n", i+1, r, r)
}
}()
panic(panicValue)
}()
}
}()
// recover 的条件
fmt.Printf(" recover 的条件:\\n")
// 正确的 recover 使用
func() {
defer func() {
if r := recover(); r != nil {
fmt.Printf(" 正确捕获 panic: %v\\n", r)
}
}()
panic("正确的 recover 示例")
}()
// 错误的 recover 使用
func() {
defer func() {
// 这个 recover 不会捕获到 panic因为不是直接在 defer 中调用
go func() {
if r := recover(); r != nil {
fmt.Printf(" 错误的 recover: %v\\n", r)
}
}()
}()
defer func() {
if r := recover(); r != nil {
fmt.Printf(" 正确捕获嵌套 panic: %v\\n", r)
}
}()
panic("嵌套 panic 示例")
}()
fmt.Println()
}
// demonstrateDeferWithPanicRecover 演示 defer 与 panic/recover 的配合
func demonstrateDeferWithPanicRecover() {
fmt.Println("3. Defer 与 Panic/Recover 的配合:")
// defer 的执行顺序
fmt.Printf(" defer 的执行顺序:\\n")
func() {
defer fmt.Printf(" defer 1\\n")
defer fmt.Printf(" defer 2\\n")
defer func() {
if r := recover(); r != nil {
fmt.Printf(" recover: %v\\n", r)
}
}()
defer fmt.Printf(" defer 3\\n")
fmt.Printf(" 正常执行\\n")
panic("测试 defer 顺序")
fmt.Printf(" 这行不会执行\\n")
}()
// 多层 defer 和 recover
fmt.Printf(" 多层 defer 和 recover:\\n")
func() {
defer func() {
fmt.Printf(" 外层 defer 开始\\n")
if r := recover(); r != nil {
fmt.Printf(" 外层 recover: %v\\n", r)
}
fmt.Printf(" 外层 defer 结束\\n")
}()
defer func() {
fmt.Printf(" 内层 defer 开始\\n")
defer func() {
if r := recover(); r != nil {
fmt.Printf(" 内层 recover: %v\\n", r)
}
}()
fmt.Printf(" 内层 defer 结束\\n")
}()
panic("多层 defer 测试")
}()
// defer 中的资源清理
fmt.Printf(" defer 中的资源清理:\\n")
processWithCleanup := func() {
// 模拟资源分配
resource := "重要资源"
fmt.Printf(" 分配资源: %s\\n", resource)
defer func() {
// 资源清理
fmt.Printf(" 清理资源: %s\\n", resource)
// 捕获 panic
if r := recover(); r != nil {
fmt.Printf(" 处理过程中发生 panic: %v\\n", r)
fmt.Printf(" 资源已安全清理\\n")
}
}()
// 模拟可能 panic 的操作
if time.Now().UnixNano()%2 == 0 {
panic("随机 panic")
}
fmt.Printf(" 正常处理完成\\n")
}
// 执行多次以演示不同情况
for i := 0; i < 3; i++ {
fmt.Printf(" 执行 %d:\\n", i+1)
processWithCleanup()
}
fmt.Println()
}
// demonstratePanicPropagation 演示 panic 的传播
func demonstratePanicPropagation() {
fmt.Println("4. Panic 的传播:")
// panic 的栈展开
fmt.Printf(" panic 的栈展开:\\n")
func() {
defer func() {
if r := recover(); r != nil {
fmt.Printf(" 最终捕获 panic: %v\\n", r)
// 打印调用栈
buf := make([]byte, 1024)
n := runtime.Stack(buf, false)
fmt.Printf(" 调用栈:\\n%s\\n", buf[:n])
}
}()
level1()
}()
// panic 的中途拦截
fmt.Printf(" panic 的中途拦截:\\n")
func() {
defer func() {
if r := recover(); r != nil {
fmt.Printf(" 最外层捕获: %v\\n", r)
}
}()
interceptedLevel1()
}()
// panic 的重新抛出
fmt.Printf(" panic 的重新抛出:\\n")
func() {
defer func() {
if r := recover(); r != nil {
fmt.Printf(" 最终处理 panic: %v\\n", r)
}
}()
rethrowLevel1()
}()
fmt.Println()
}
// demonstratePracticalUsage 演示 panic/recover 的实际应用
func demonstratePracticalUsage() {
fmt.Println("5. Panic/Recover 的实际应用:")
// Web 服务器中的 panic 恢复
fmt.Printf(" Web 服务器中的 panic 恢复:\\n")
requests := []string{
"/api/users",
"/api/panic",
"/api/orders",
"/api/error",
}
for _, path := range requests {
handleHTTPRequest(path)
}
// 工作池中的 panic 处理
fmt.Printf(" 工作池中的 panic 处理:\\n")
jobs := []Job{
{ID: 1, Data: "正常任务"},
{ID: 2, Data: "panic任务"},
{ID: 3, Data: "正常任务"},
{ID: 4, Data: "error任务"},
}
for _, job := range jobs {
processJobSafely(job)
}
// 数据解析中的 panic 处理
fmt.Printf(" 数据解析中的 panic 处理:\\n")
data := []string{
"123",
"abc",
"456",
"",
"789",
}
for _, item := range data {
result := parseIntSafely(item)
fmt.Printf(" 解析 '%s': %d\\n", item, result)
}
// 递归函数中的 panic 处理
fmt.Printf(" 递归函数中的 panic 处理:\\n")
testValues := []int{5, -1, 10, 0}
for _, n := range testValues {
result := safeFactorial(n)
fmt.Printf(" %d! = %d\\n", n, result)
}
fmt.Println()
}
// demonstrateBestPractices 演示最佳实践
func demonstrateBestPractices() {
fmt.Println("6. 最佳实践:")
// 最佳实践原则
fmt.Printf(" 最佳实践原则:\\n")
fmt.Printf(" 1. 优先使用错误返回值而不是 panic\\n")
fmt.Printf(" 2. 只在真正异常的情况下使用 panic\\n")
fmt.Printf(" 3. 在库代码中避免 panic转换为错误\\n")
fmt.Printf(" 4. 在应用边界使用 recover 保护\\n")
fmt.Printf(" 5. 记录 panic 信息用于调试\\n")
// 库函数的 panic 处理
fmt.Printf(" 库函数的 panic 处理:\\n")
// 不好的做法:库函数直接 panic
fmt.Printf(" 不好的做法示例:\\n")
result, err := callLibraryFunction("invalid")
if err != nil {
fmt.Printf(" 库函数错误: %v\\n", err)
} else {
fmt.Printf(" 库函数结果: %s\\n", result)
}
// 好的做法:将 panic 转换为错误
fmt.Printf(" 好的做法示例:\\n")
result, err = safeLibraryFunction("invalid")
if err != nil {
fmt.Printf(" 安全库函数错误: %v\\n", err)
} else {
fmt.Printf(" 安全库函数结果: %s\\n", result)
}
// panic 信息的记录
fmt.Printf(" panic 信息的记录:\\n")
func() {
defer func() {
if r := recover(); r != nil {
logPanic(r)
}
}()
panic("需要记录的 panic")
}()
// 优雅的服务关闭
fmt.Printf(" 优雅的服务关闭:\\n")
server := &Server{name: "测试服务器"}
server.Start()
// 模拟服务运行中的 panic
func() {
defer server.handlePanic()
panic("服务运行时错误")
}()
server.Stop()
fmt.Println()
}
// demonstrateErrorVsPanic 演示错误处理 vs panic 的选择
func demonstrateErrorVsPanic() {
fmt.Println("7. 错误处理 vs Panic 的选择:")
// 使用错误的场景
fmt.Printf(" 使用错误的场景:\\n")
fmt.Printf(" - 预期可能发生的错误\\n")
fmt.Printf(" - 用户输入错误\\n")
fmt.Printf(" - 网络或I/O错误\\n")
fmt.Printf(" - 业务逻辑错误\\n")
// 使用 panic 的场景
fmt.Printf(" 使用 panic 的场景:\\n")
fmt.Printf(" - 程序逻辑错误\\n")
fmt.Printf(" - 不可恢复的错误\\n")
fmt.Printf(" - 初始化失败\\n")
fmt.Printf(" - 断言失败\\n")
// 对比示例
fmt.Printf(" 对比示例:\\n")
// 错误处理示例
fmt.Printf(" 错误处理示例:\\n")
result, err := divide(10, 0)
if err != nil {
fmt.Printf(" 除法错误: %v\\n", err)
} else {
fmt.Printf(" 除法结果: %.2f\\n", result)
}
// panic 示例
fmt.Printf(" panic 示例:\\n")
func() {
defer func() {
if r := recover(); r != nil {
fmt.Printf(" 捕获 panic: %v\\n", r)
}
}()
assertPositive(-5)
}()
// 混合使用示例
fmt.Printf(" 混合使用示例:\\n")
calculator := &Calculator{}
// 正常计算
result, err = calculator.Calculate("10 + 5")
if err != nil {
fmt.Printf(" 计算错误: %v\\n", err)
} else {
fmt.Printf(" 计算结果: %.2f\\n", result)
}
// 无效表达式
result, err = calculator.Calculate("invalid")
if err != nil {
fmt.Printf(" 计算错误: %v\\n", err)
} else {
fmt.Printf(" 计算结果: %.2f\\n", result)
}
// 内部 panic 被转换为错误
result, err = calculator.Calculate("panic")
if err != nil {
fmt.Printf(" 计算错误: %v\\n", err)
} else {
fmt.Printf(" 计算结果: %.2f\\n", result)
}
fmt.Println()
}
// ========== 辅助函数和类型定义 ==========
// safeFunction 安全执行函数
func safeFunction(fn func() int) int {
defer func() {
if r := recover(); r != nil {
fmt.Printf(" 函数执行中发生 panic已恢复: %v\\n", r)
}
}()
return fn()
}
// level1 第一层函数
func level1() {
defer func() {
fmt.Printf(" level1 defer 执行\\n")
}()
fmt.Printf(" 进入 level1\\n")
level2()
fmt.Printf(" level1 正常结束\\n")
}
// level2 第二层函数
func level2() {
defer func() {
fmt.Printf(" level2 defer 执行\\n")
}()
fmt.Printf(" 进入 level2\\n")
level3()
fmt.Printf(" level2 正常结束\\n")
}
// level3 第三层函数
func level3() {
defer func() {
fmt.Printf(" level3 defer 执行\\n")
}()
fmt.Printf(" 进入 level3\\n")
panic("level3 中的 panic")
fmt.Printf(" level3 正常结束\\n")
}
// interceptedLevel1 中途拦截的第一层
func interceptedLevel1() {
defer func() {
fmt.Printf(" interceptedLevel1 defer\\n")
}()
fmt.Printf(" 进入 interceptedLevel1\\n")
interceptedLevel2()
fmt.Printf(" interceptedLevel1 正常结束\\n")
}
// interceptedLevel2 中途拦截的第二层
func interceptedLevel2() {
defer func() {
if r := recover(); r != nil {
fmt.Printf(" interceptedLevel2 拦截 panic: %v\\n", r)
// 不重新抛出panic 在这里被处理
}
fmt.Printf(" interceptedLevel2 defer\\n")
}()
fmt.Printf(" 进入 interceptedLevel2\\n")
interceptedLevel3()
fmt.Printf(" interceptedLevel2 正常结束\\n")
}
// interceptedLevel3 中途拦截的第三层
func interceptedLevel3() {
defer func() {
fmt.Printf(" interceptedLevel3 defer\\n")
}()
fmt.Printf(" 进入 interceptedLevel3\\n")
panic("interceptedLevel3 中的 panic")
fmt.Printf(" interceptedLevel3 正常结束\\n")
}
// rethrowLevel1 重新抛出的第一层
func rethrowLevel1() {
defer func() {
fmt.Printf(" rethrowLevel1 defer\\n")
}()
fmt.Printf(" 进入 rethrowLevel1\\n")
rethrowLevel2()
fmt.Printf(" rethrowLevel1 正常结束\\n")
}
// rethrowLevel2 重新抛出的第二层
func rethrowLevel2() {
defer func() {
if r := recover(); r != nil {
fmt.Printf(" rethrowLevel2 捕获并重新抛出 panic: %v\\n", r)
panic(fmt.Sprintf("重新抛出: %v", r)) // 重新抛出
}
fmt.Printf(" rethrowLevel2 defer\\n")
}()
fmt.Printf(" 进入 rethrowLevel2\\n")
rethrowLevel3()
fmt.Printf(" rethrowLevel2 正常结束\\n")
}
// rethrowLevel3 重新抛出的第三层
func rethrowLevel3() {
defer func() {
fmt.Printf(" rethrowLevel3 defer\\n")
}()
fmt.Printf(" 进入 rethrowLevel3\\n")
panic("rethrowLevel3 中的 panic")
fmt.Printf(" rethrowLevel3 正常结束\\n")
}
// handleHTTPRequest 处理HTTP请求
func handleHTTPRequest(path string) {
defer func() {
if r := recover(); r != nil {
fmt.Printf(" HTTP请求 %s 发生 panic已恢复: %v\\n", path, r)
// 在实际应用中,这里会返回 500 错误
}
}()
fmt.Printf(" 处理请求: %s\\n", path)
switch path {
case "/api/panic":
panic("模拟处理器 panic")
case "/api/error":
// 这里应该返回错误而不是 panic
fmt.Printf(" 请求处理出错\\n")
default:
fmt.Printf(" 请求处理成功\\n")
}
}
// Job 任务结构
type Job struct {
ID int
Data string
}
// processJobSafely 安全处理任务
func processJobSafely(job Job) {
defer func() {
if r := recover(); r != nil {
fmt.Printf(" 任务 %d 处理时发生 panic已恢复: %v\\n", job.ID, r)
}
}()
fmt.Printf(" 处理任务 %d: %s\\n", job.ID, job.Data)
switch job.Data {
case "panic任务":
panic("任务处理中的 panic")
case "error任务":
fmt.Printf(" 任务处理出错\\n")
default:
fmt.Printf(" 任务处理成功\\n")
}
}
// parseIntSafely 安全解析整数
func parseIntSafely(s string) int {
defer func() {
if r := recover(); r != nil {
fmt.Printf(" 解析 '%s' 时发生 panic: %v\\n", s, r)
}
}()
if s == "" {
panic("空字符串无法解析")
}
result, err := strconv.Atoi(s)
if err != nil {
return 0 // 返回默认值
}
return result
}
// safeFactorial 安全计算阶乘
func safeFactorial(n int) int {
defer func() {
if r := recover(); r != nil {
fmt.Printf(" 计算 %d! 时发生 panic: %v\\n", n, r)
}
}()
return factorial(n)
}
// factorial 计算阶乘(可能 panic
func factorial(n int) int {
if n < 0 {
panic("负数没有阶乘")
}
if n == 0 || n == 1 {
return 1
}
return n * factorial(n-1)
}
// callLibraryFunction 库函数(不好的做法)
func callLibraryFunction(input string) (string, error) {
// 这个函数直接 panic不是好的做法
if input == "invalid" {
panic("库函数中的 panic")
}
return "处理结果: " + input, nil
}
// safeLibraryFunction 安全的库函数
func safeLibraryFunction(input string) (result string, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("库函数内部错误: %v", r)
}
}()
// 调用可能 panic 的函数
return callLibraryFunction(input)
}
// logPanic 记录 panic 信息
func logPanic(r interface{}) {
fmt.Printf(" [PANIC LOG] 时间: %s\\n", time.Now().Format("2006-01-02 15:04:05"))
fmt.Printf(" [PANIC LOG] 错误: %v\\n", r)
fmt.Printf(" [PANIC LOG] 类型: %T\\n", r)
// 获取调用栈
buf := make([]byte, 1024)
n := runtime.Stack(buf, false)
fmt.Printf(" [PANIC LOG] 调用栈:\\n%s\\n", buf[:n])
}
// Server 服务器结构
type Server struct {
name string
}
func (s *Server) Start() {
fmt.Printf(" 服务器 %s 启动\\n", s.name)
}
func (s *Server) Stop() {
fmt.Printf(" 服务器 %s 停止\\n", s.name)
}
func (s *Server) handlePanic() {
if r := recover(); r != nil {
fmt.Printf(" 服务器 %s 捕获 panic: %v\\n", s.name, r)
fmt.Printf(" 服务器继续运行\\n")
}
}
// divide 除法运算
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("除数不能为零")
}
return a / b, nil
}
// assertPositive 断言为正数
func assertPositive(n int) {
if n <= 0 {
panic(fmt.Sprintf("断言失败: %d 不是正数", n))
}
fmt.Printf(" 断言通过: %d 是正数\\n", n)
}
// Calculator 计算器
type Calculator struct{}
func (c *Calculator) Calculate(expression string) (result float64, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("计算表达式 '%s' 时发生内部错误: %v", expression, r)
}
}()
switch expression {
case "10 + 5":
return 15, nil
case "invalid":
return 0, fmt.Errorf("无效的表达式: %s", expression)
case "panic":
panic("计算器内部 panic")
default:
return 0, fmt.Errorf("不支持的表达式: %s", expression)
}
}
/*
运行这个程序:
go run 03-panic-recover.go
学习要点:
1. panic 是运行时错误,会导致程序崩溃
2. recover 只能在 defer 函数中使用来捕获 panic
3. defer 语句按照 LIFO 顺序执行
4. panic 会沿着调用栈向上传播
5. panic/recover 应该谨慎使用,优先使用错误处理
Panic 的特性:
1. 停止当前函数的正常执行
2. 执行当前函数的所有 defer 语句
3. 向上传播到调用函数
4. 如果没有被 recover程序会崩溃
5. 可以携带任意类型的值
Recover 的特性:
1. 只能在 defer 函数中直接调用
2. 返回 panic 的值,如果没有 panic 返回 nil
3. 只能捕获当前 goroutine 的 panic
4. 捕获后程序可以继续执行
5. 可以根据 panic 值进行不同处理
常见的 Panic 场景:
1. 数组或切片越界访问
2. 空指针解引用
3. 类型断言失败(不安全断言)
4. 向已关闭的 channel 发送数据
5. 除零操作(整数除法)
使用场景:
1. Panic 适用场景:
- 程序逻辑错误
- 不可恢复的错误
- 初始化失败
- 断言失败
2. Error 适用场景:
- 预期可能发生的错误
- 用户输入错误
- 网络或I/O错误
- 业务逻辑错误
最佳实践:
1. 优先使用错误返回值而不是 panic
2. 只在真正异常的情况下使用 panic
3. 在库代码中避免 panic转换为错误
4. 在应用边界使用 recover 保护
5. 记录 panic 信息用于调试
6. 使用 defer 进行资源清理
注意事项:
1. recover 只能在 defer 中直接调用
2. 不要忽略 recover 的返回值
3. panic 会影响程序性能
4. 过度使用 panic/recover 会使代码难以理解
5. 在 goroutine 中的 panic 需要单独处理
实际应用:
1. Web 服务器的 panic 恢复中间件
2. 工作池中的任务 panic 处理
3. 数据解析中的异常处理
4. 递归函数的栈溢出保护
5. 库函数的 panic 转错误
性能考虑:
1. panic/recover 有一定的性能开销
2. 不应该用于正常的控制流
3. 频繁的 panic/recover 会影响性能
4. 错误处理通常比 panic/recover 更高效
5. 在性能敏感的代码中谨慎使用
*/