Files
golang/golang-learning/09-advanced/02-generics.go
2025-08-24 13:01:09 +08:00

561 lines
15 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
02-generics.go - Go 语言泛型详解
学习目标:
1. 理解泛型的概念和优势
2. 掌握类型参数的定义和使用
3. 学会类型约束的应用
4. 了解泛型函数和泛型类型
5. 掌握泛型的最佳实践
知识点:
- 泛型的基本概念
- 类型参数和类型约束
- 泛型函数和泛型类型
- 内置约束和自定义约束
- 类型推断
- 泛型的实际应用
注意:此示例需要 Go 1.18 或更高版本
*/
package main
import (
"fmt"
"sort"
"strconv"
"strings"
)
func main() {
fmt.Println("=== Go 语言泛型详解 ===\\n")
// 演示泛型的基本概念
demonstrateGenericsBasics()
// 演示泛型函数
demonstrateGenericFunctions()
// 演示泛型类型
demonstrateGenericTypes()
// 演示类型约束
demonstrateTypeConstraints()
// 演示内置约束
demonstrateBuiltinConstraints()
// 演示泛型的实际应用
demonstratePracticalApplications()
// 演示泛型的最佳实践
demonstrateBestPractices()
}
// demonstrateGenericsBasics 演示泛型的基本概念
func demonstrateGenericsBasics() {
fmt.Println("1. 泛型的基本概念:")
// 泛型的基本概念
fmt.Printf(" 泛型的基本概念:\\n")
fmt.Printf(" - 泛型允许编写可重用的代码\\n")
fmt.Printf(" - 类型参数在编译时确定具体类型\\n")
fmt.Printf(" - 提供类型安全的抽象\\n")
fmt.Printf(" - Go 1.18+ 支持泛型\\n")
fmt.Printf(" - 减少代码重复和类型断言\\n")
// 泛型语法
fmt.Printf(" 泛型语法:\\n")
fmt.Printf(" 函数泛型: func Name[T any](param T) T\\n")
fmt.Printf(" 类型泛型: type Name[T any] struct { field T }\\n")
fmt.Printf(" 约束语法: func Name[T Constraint](param T) T\\n")
// 简单泛型函数示例
fmt.Printf(" 简单泛型函数示例:\\n")
// 使用泛型函数
fmt.Printf(" 整数最大值: %d\\n", Max(10, 20))
fmt.Printf(" 浮点数最大值: %.2f\\n", Max(3.14, 2.71))
fmt.Printf(" 字符串最大值: %s\\n", Max("apple", "banana"))
// 类型推断
fmt.Printf(" 类型推断:\\n")
fmt.Printf(" Go 编译器可以自动推断类型参数\\n")
// 显式指定类型参数
result1 := Max[int](5, 8)
fmt.Printf(" 显式指定类型: %d\\n", result1)
// 自动类型推断
result2 := Max(5, 8)
fmt.Printf(" 自动类型推断: %d\\n", result2)
// 泛型的优势
fmt.Printf(" 泛型的优势:\\n")
fmt.Printf(" 1. 类型安全:编译时检查类型\\n")
fmt.Printf(" 2. 代码复用:一套代码支持多种类型\\n")
fmt.Printf(" 3. 性能优化:避免运行时类型断言\\n")
fmt.Printf(" 4. 可读性:减少重复代码\\n")
fmt.Printf(" 5. 维护性:统一的逻辑实现\\n")
fmt.Println()
}
// demonstrateGenericFunctions 演示泛型函数
func demonstrateGenericFunctions() {
fmt.Println("2. 泛型函数:")
// 基本泛型函数
fmt.Printf(" 基本泛型函数:\\n")
// 交换函数
a, b := 10, 20
fmt.Printf(" 交换前: a=%d, b=%d\\n", a, b)
a, b = Swap(a, b)
fmt.Printf(" 交换后: a=%d, b=%d\\n", a, b)
str1, str2 := "hello", "world"
fmt.Printf(" 交换前: str1=%s, str2=%s\\n", str1, str2)
str1, str2 = Swap(str1, str2)
fmt.Printf(" 交换后: str1=%s, str2=%s\\n", str1, str2)
// 查找函数
fmt.Printf(" 查找函数:\\n")
numbers := []int{1, 2, 3, 4, 5}
index := Find(numbers, 3)
fmt.Printf(" 在 %v 中查找 3: 索引 %d\\n", numbers, index)
words := []string{"apple", "banana", "cherry"}
index = Find(words, "banana")
fmt.Printf(" 在 %v 中查找 banana: 索引 %d\\n", words, index)
// 映射函数
fmt.Printf(" 映射函数:\\n")
// 数字平方
squares := Map([]int{1, 2, 3, 4, 5}, func(x int) int {
return x * x
})
fmt.Printf(" 数字平方: %v\\n", squares)
// 字符串长度
lengths := Map([]string{"go", "rust", "python"}, func(s string) int {
return len(s)
})
fmt.Printf(" 字符串长度: %v\\n", lengths)
// 过滤函数
fmt.Printf(" 过滤函数:\\n")
// 过滤偶数
evens := Filter([]int{1, 2, 3, 4, 5, 6}, func(x int) bool {
return x%2 == 0
})
fmt.Printf(" 偶数: %v\\n", evens)
// 过滤长字符串
longWords := Filter([]string{"go", "rust", "python", "javascript"}, func(s string) bool {
return len(s) > 4
})
fmt.Printf(" 长单词: %v\\n", longWords)
// 归约函数
fmt.Printf(" 归约函数:\\n")
// 求和
sum := Reduce([]int{1, 2, 3, 4, 5}, 0, func(acc, x int) int {
return acc + x
})
fmt.Printf(" 数组求和: %d\\n", sum)
// 字符串连接
concat := Reduce([]string{"Hello", " ", "World", "!"}, "", func(acc, s string) string {
return acc + s
})
fmt.Printf(" 字符串连接: %s\\n", concat)
// 多类型参数函数
fmt.Printf(" 多类型参数函数:\\n")
pairs := Zip([]int{1, 2, 3}, []string{"a", "b", "c"})
fmt.Printf(" 配对结果: %v\\n", pairs)
fmt.Println()
}
// demonstrateGenericTypes 演示泛型类型
func demonstrateGenericTypes() {
fmt.Println("3. 泛型类型:")
// 泛型栈
fmt.Printf(" 泛型栈:\\n")
// 整数栈
intStack := NewStack[int]()
intStack.Push(1)
intStack.Push(2)
intStack.Push(3)
fmt.Printf(" 整数栈大小: %d\\n", intStack.Size())
for !intStack.IsEmpty() {
value, _ := intStack.Pop()
fmt.Printf(" 弹出: %d\\n", value)
}
// 字符串栈
strStack := NewStack[string]()
strStack.Push("first")
strStack.Push("second")
strStack.Push("third")
fmt.Printf(" 字符串栈内容:\\n")
for !strStack.IsEmpty() {
value, _ := strStack.Pop()
fmt.Printf(" %s\\n", value)
}
// 泛型队列
fmt.Printf(" 泛型队列:\\n")
queue := NewQueue[string]()
queue.Enqueue("first")
queue.Enqueue("second")
queue.Enqueue("third")
fmt.Printf(" 队列大小: %d\\n", queue.Size())
for !queue.IsEmpty() {
value, _ := queue.Dequeue()
fmt.Printf(" 出队: %s\\n", value)
}
// 泛型映射
fmt.Printf(" 泛型映射:\\n")
cache := NewCache[string, int]()
cache.Set("apple", 5)
cache.Set("banana", 3)
cache.Set("cherry", 8)
if value, ok := cache.Get("apple"); ok {
fmt.Printf(" apple 的值: %d\\n", value)
}
fmt.Printf(" 缓存大小: %d\\n", cache.Size())
fmt.Printf(" 所有键: %v\\n", cache.Keys())
// 泛型链表
fmt.Printf(" 泛型链表:\\n")
list := NewLinkedList[int]()
list.Add(1)
list.Add(2)
list.Add(3)
fmt.Printf(" 链表大小: %d\\n", list.Size())
fmt.Printf(" 链表内容: %v\\n", list.ToSlice())
if list.Contains(2) {
fmt.Printf(" 链表包含 2\\n")
}
list.Remove(2)
fmt.Printf(" 删除 2 后: %v\\n", list.ToSlice())
fmt.Println()
}
// demonstrateTypeConstraints 演示类型约束
func demonstrateTypeConstraints() {
fmt.Println("4. 类型约束:")
// 基本约束
fmt.Printf(" 基本约束:\\n")
fmt.Printf(" any: 任意类型\\n")
fmt.Printf(" comparable: 可比较类型\\n")
// 自定义约束
fmt.Printf(" 自定义约束:\\n")
// 数值类型约束
fmt.Printf(" 数值类型约束:\\n")
fmt.Printf(" 整数求和: %d\\n", Sum([]int{1, 2, 3, 4, 5}))
fmt.Printf(" 浮点数求和: %.2f\\n", Sum([]float64{1.1, 2.2, 3.3}))
// 有序类型约束
fmt.Printf(" 有序类型约束:\\n")
intSlice := []int{3, 1, 4, 1, 5, 9}
fmt.Printf(" 排序前: %v\\n", intSlice)
SortSlice(intSlice)
fmt.Printf(" 排序后: %v\\n", intSlice)
strSlice := []string{"banana", "apple", "cherry"}
fmt.Printf(" 排序前: %v\\n", strSlice)
SortSlice(strSlice)
fmt.Printf(" 排序后: %v\\n", strSlice)
// 字符串化约束
fmt.Printf(" 字符串化约束:\\n")
fmt.Printf(" 整数转字符串: %s\\n", ToString(42))
fmt.Printf(" 浮点数转字符串: %s\\n", ToString(3.14))
fmt.Printf(" 布尔值转字符串: %s\\n", ToString(true))
// 接口约束
fmt.Printf(" 接口约束:\\n")
shapes := []Shape{
Rectangle{Width: 5, Height: 3},
Circle{Radius: 4},
}
totalArea := CalculateTotalArea(shapes)
fmt.Printf(" 总面积: %.2f\\n", totalArea)
// 类型集合约束
fmt.Printf(" 类型集合约束:\\n")
fmt.Printf(" 整数绝对值: %d\\n", Abs(-42))
fmt.Printf(" 浮点数绝对值: %.2f\\n", Abs(-3.14))
fmt.Println()
}
// demonstrateBuiltinConstraints 演示内置约束
func demonstrateBuiltinConstraints() {
fmt.Println("5. 内置约束:")
// comparable 约束
fmt.Printf(" comparable 约束:\\n")
// 可比较类型的相等检查
fmt.Printf(" 整数相等: %t\\n", Equal(5, 5))
fmt.Printf(" 字符串相等: %t\\n", Equal("hello", "hello"))
fmt.Printf(" 布尔值相等: %t\\n", Equal(true, false))
// 可比较类型的去重
duplicateInts := []int{1, 2, 2, 3, 3, 3, 4}
uniqueInts := Unique(duplicateInts)
fmt.Printf(" 整数去重: %v -> %v\\n", duplicateInts, uniqueInts)
duplicateStrs := []string{"a", "b", "b", "c", "c", "c"}
uniqueStrs := Unique(duplicateStrs)
fmt.Printf(" 字符串去重: %v -> %v\\n", duplicateStrs, uniqueStrs)
// any 约束
fmt.Printf(" any 约束:\\n")
// 任意类型的容器
container := NewContainer[any]()
container.Add(42)
container.Add("hello")
container.Add(3.14)
container.Add(true)
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)
}
// 类型断言与泛型
fmt.Printf(" 类型断言与泛型:\\n")
values := []any{42, "hello", 3.14, true}
// 提取特定类型
strings := ExtractType[string](values)
fmt.Printf(" 提取字符串: %v\\n", strings)
numbers := ExtractType[int](values)
fmt.Printf(" 提取整数: %v\\n", numbers)
fmt.Println()
}
// demonstratePracticalApplications 演示泛型的实际应用
func demonstratePracticalApplications() {
fmt.Println("6. 泛型的实际应用:")
// 应用1: 泛型数据结构
fmt.Printf(" 应用1 - 泛型数据结构:\\n")
// 优先队列
pq := NewPriorityQueue[int]()
pq.Push(3, 3)
pq.Push(1, 1)
pq.Push(4, 4)
pq.Push(2, 2)
fmt.Printf(" 优先队列出队顺序:\\n")
for !pq.IsEmpty() {
item, priority := pq.Pop()
fmt.Printf(" 项目: %v, 优先级: %d\\n", item, priority)
}
// 应用2: 泛型算法
fmt.Printf(" 应用2 - 泛型算法:\\n")
// 二分查找
sortedInts := []int{1, 3, 5, 7, 9, 11, 13}
index := BinarySearch(sortedInts, 7)
fmt.Printf(" 二分查找 7 在 %v 中的位置: %d\\n", sortedInts, index)
sortedStrs := []string{"apple", "banana", "cherry", "date"}
index = BinarySearch(sortedStrs, "cherry")
fmt.Printf(" 二分查找 cherry 在 %v 中的位置: %d\\n", sortedStrs, index)
// 应用3: 泛型工具函数
fmt.Printf(" 应用3 - 泛型工具函数:\\n")
// 切片操作
original := []int{1, 2, 3, 4, 5}
// 反转
reversed := Reverse(original)
fmt.Printf(" 反转: %v -> %v\\n", original, reversed)
// 分块
chunks := Chunk(original, 2)
fmt.Printf(" 分块(大小2): %v -> %v\\n", original, chunks)
// 去重并排序
unsorted := []int{3, 1, 4, 1, 5, 9, 2, 6, 5}
uniqueSorted := UniqueAndSort(unsorted)
fmt.Printf(" 去重排序: %v -> %v\\n", unsorted, uniqueSorted)
// 应用4: 泛型缓存
fmt.Printf(" 应用4 - 泛型缓存:\\n")
lruCache := NewLRUCache[string, string](3)
lruCache.Put("a", "apple")
lruCache.Put("b", "banana")
lruCache.Put("c", "cherry")
fmt.Printf(" 缓存状态: %v\\n", lruCache.Keys())
// 访问会更新顺序
if value, ok := lruCache.Get("a"); ok {
fmt.Printf(" 获取 a: %s\\n", value)
}
// 添加新项会淘汰最久未使用的
lruCache.Put("d", "date")
fmt.Printf(" 添加 d 后: %v\\n", lruCache.Keys())
// 应用5: 泛型验证器
fmt.Printf(" 应用5 - 泛型验证器:\\n")
validator := NewValidator[User]()
// 添加验证规则
validator.AddRule(\"name\", func(u User) bool {
return len(u.Name) > 0
}, \"姓名不能为空\")
validator.AddRule(\"age\", func(u User) bool {
return u.Age >= 0 && u.Age <= 150
}, \"年龄必须在0-150之间\")
validator.AddRule(\"email\", func(u User) bool {
return strings.Contains(u.Email, \"@\")
}, \"邮箱格式不正确\")
// 验证用户
validUser := User{Name: \"Alice\", Age: 25, Email: \"alice@example.com\"}
invalidUser := User{Name: \"\", Age: -5, Email: \"invalid\"}
if errors := validator.Validate(validUser); len(errors) == 0 {
fmt.Printf(" 有效用户验证通过\\n")
} else {
fmt.Printf(" 有效用户验证失败: %v\\n", errors)
}
if errors := validator.Validate(invalidUser); len(errors) > 0 {
fmt.Printf(" 无效用户验证失败: %v\\n", errors)
}
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. 避免过度泛型化\\n")
fmt.Printf(" 5. 考虑编译时间和代码复杂度\\n")
// 命名约定
fmt.Printf(" 命名约定:\\n")
fmt.Printf(" - T: 通用类型参数\\n")
fmt.Printf(" - K, V: 键值对类型\\n")
fmt.Printf(" - E: 元素类型\\n")
fmt.Printf(" - R: 结果类型\\n")
fmt.Printf(" - 使用描述性名称: TKey, TValue, TElement\\n")
// 约束设计
fmt.Printf(" 约束设计:\\n")
fmt.Printf(" - 使用最小必要约束\\n")
fmt.Printf(" - 优先使用内置约束\\n")
fmt.Printf(" - 自定义约束要有明确语义\\n")
fmt.Printf(" - 避免过于复杂的约束\\n")
// 性能考虑
fmt.Printf(" 性能考虑:\\n")
// 泛型 vs 接口性能对比
fmt.Printf(" 泛型 vs 接口性能对比:\\n")
// 泛型版本
start := time.Now()
genericSum := 0
for i := 0; i < 1000000; i++ {
genericSum = Add(genericSum, 1)
}
genericTime := time.Since(start)
// 接口版本
start = time.Now()
var interfaceSum Addable = IntValue(0)
for i := 0; i < 1000000; i++ {
interfaceSum = interfaceSum.Add(IntValue(1))
}
interfaceTime := time.Since(start)
fmt.Printf(" 泛型版本耗时: %v\\n", genericTime)
fmt.Printf(" 接口版本耗时: %v\\n", interfaceTime)
fmt.Printf(" 性能提升: %.2fx\\n", float64(interfaceTime)/float64(genericTime))
// 何时使用泛型
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")
fmt.Printf(" 过度抽象的设计\\n")
fmt.Printf(" 性能敏感且类型固定的代码\\n")
// 迁移策略
fmt.Printf(" 迁移策略:\\n")
fmt.Printf(" 1. 识别重复代码模式\\n")
fmt.Printf(" 2. 从简单场景开始\\n")
fmt.Printf(" 3. 逐步替换类型断言\\n")
fmt.Printf(" 4. 保持向后兼容\\n")
fmt.Printf(" 5. 充分测试泛型代码\\n")
fmt.Println()
}