561 lines
15 KiB
Go
561 lines
15 KiB
Go
/*
|
||
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()
|
||
} |