flyfei

Go语言泛型

1. 语法/理论讲解

基本语法

// 泛型函数
func 函数名[T 约束](参数 T) T {
    // 函数体
}

// 泛型结构体
type 结构体名[T 约束] struct {
    字段 T
}

关键概念

为什么要用泛型?

// 传统方式:为每种类型写重复代码
func MaxInt(a, b int) int {
    if a > b { return a }
    return b
}

func MaxFloat(a, b float64) float64 {
    if a > b { return a }
    return b
}

// 泛型方式:一个函数搞定
func Max[T cmp.Ordered](a, b T) T {
    if a > b { return a }
    return b
}

2. 应用场景

  1. 通用数据结构
    • 栈、队列、链表等容器
    • 集合操作
  2. 工具函数
    • 比较、排序、查找
    • 数学运算
  3. 数据处理
    • 映射、过滤、归约操作
    • 数据转换
  4. 避免interface{}和类型断言
    • 类型安全
    • 更好的性能

3. 编程示例

基础泛型函数

package main

import "fmt"

// 任何类型都可以
func PrintSlice[T any](s []T) {
    for _, v := range s {
        fmt.Print(v, " ")
    }
    fmt.Println()
}

// 可比较的类型
func FindIndex[T comparable](slice []T, target T) int {
    for i, v := range slice {
        if v == target {
            return i
        }
    }
    return -1
}

// 使用示例
func main() {
    // 整数切片
    intSlice := []int{1, 2, 3, 4, 5}
    PrintSlice(intSlice)
    fmt.Println("索引:", FindIndex(intSlice, 3))
    
    // 字符串切片
    strSlice := []string{"apple", "banana", "cherry"}
    PrintSlice(strSlice)
    fmt.Println("索引:", FindIndex(strSlice, "banana"))
    
    // 自动类型推断
    fmt.Println("最大值:", Max(10, 20))
    fmt.Println("最大值:", Max(3.14, 2.71))
}

自定义类型约束

package main

import (
    "fmt"
    "strings"
)

// 自定义约束:要求类型支持String()方法
type Stringer interface {
    String() string
}

// 数值类型约束
type Number interface {
    int | int8 | int16 | int32 | int64 | 
    uint | uint8 | uint16 | uint32 | uint64 |
    float32 | float64
}

// 使用自定义约束的函数
func PrintAll[T Stringer](items []T) {
    for _, item := range items {
        fmt.Println(item.String())
    }
}

// 数值运算
func Sum[T Number](numbers []T) T {
    var sum T
    for _, num := range numbers {
        sum += num
    }
    return sum
}

func Average[T Number](numbers []T) float64 {
    if len(numbers) == 0 {
        return 0
    }
    sum := Sum(numbers)
    return float64(sum) / float64(len(numbers))
}

// 实现Stringer接口的类型
type Person struct {
    Name string
    Age  int
}

func (p Person) String() string {
    return fmt.Sprintf("%s (%d岁)", p.Name, p.Age)
}

type Product struct {
    Name  string
    Price float64
}

func (p Product) String() string {
    return fmt.Sprintf("%s - ¥%.2f", p.Name, p.Price)
}

// 使用示例
func main() {
    // 使用Stringer约束
    people := []Person{
        {"张三", 25},
        {"李四", 30},
    }
    PrintAll(people)
    
    products := []Product{
        {"手机", 2999.99},
        {"电脑", 5999.50},
    }
    PrintAll(products)
    
    // 使用数值约束
    ints := []int{1, 2, 3, 4, 5}
    floats := []float64{1.1, 2.2, 3.3, 4.4, 5.5}
    
    fmt.Println("整数和:", Sum(ints))
    fmt.Println("浮点数和:", Sum(floats))
    fmt.Println("整数平均值:", Average(ints))
    fmt.Println("浮点数平均值:", Average(floats))
}

实用工具函数

package main

import "fmt"

// 映射函数:将切片中的每个元素转换为另一种类型
func Map[T, U any](slice []T, f func(T) U) []U {
    result := make([]U, len(slice))
    for i, v := range slice {
        result[i] = f(v)
    }
    return result
}

// 过滤函数:过滤出满足条件的元素
func Filter[T any](slice []T, f func(T) bool) []T {
    var result []T
    for _, v := range slice {
        if f(v) {
            result = append(result, v)
        }
    }
    return result
}

// 归约函数:将切片归约为单个值
func Reduce[T, U any](slice []T, initial U, f func(U, T) U) U {
    result := initial
    for _, v := range slice {
        result = f(result, v)
    }
    return result
}

// 包含判断
func Contains[T comparable](slice []T, target T) bool {
    for _, v := range slice {
        if v == target {
            return true
        }
    }
    return false
}

// 去重
func Unique[T comparable](slice []T) []T {
    seen := make(map[T]bool)
    var result []T
    for _, v := range slice {
        if !seen[v] {
            seen[v] = true
            result = append(result, v)
        }
    }
    return result
}

// 使用示例
func main() {
    numbers := []int{1, 2, 3, 4, 5, 2, 3, 4}
    
    // 映射:将数字转换为字符串
    strings := Map(numbers, func(n int) string {
        return fmt.Sprintf("数字%d", n)
    })
    fmt.Println("映射结果:", strings)
    
    // 过滤:只保留偶数
    evens := Filter(numbers, func(n int) bool {
        return n%2 == 0
    })
    fmt.Println("偶数:", evens)
    
    // 归约:求和
    sum := Reduce(numbers, 0, func(acc, n int) int {
        return acc + n
    })
    fmt.Println("总和:", sum)
    
    // 包含判断
    fmt.Println("包含3:", Contains(numbers, 3))
    fmt.Println("包含10:", Contains(numbers, 10))
    
    // 去重
    uniqueNumbers := Unique(numbers)
    fmt.Println("去重后:", uniqueNumbers)
}

4. 其他用法

泛型结构体

// 泛型键值对
type Pair[K comparable, V any] struct {
    Key   K
    Value V
}

// 使用示例
func main() {
    // 字符串-整数对
    pair1 := Pair[string, int]{"age", 25}
    
    // 整数-字符串对  
    pair2 := Pair[int, string]{1, "one"}
    
    fmt.Printf("对1: %s=%d\n", pair1.Key, pair1.Value)
    fmt.Printf("对2: %d=%s\n", pair2.Key, pair2.Value)
}

5.课程总结

  1. 泛型是什么:编写类型安全的通用代码
  2. 核心语法[T 约束]anycomparable、自定义约束
  3. 应用场景:通用数据结构、工具函数、数据处理
  4. 优势:类型安全、减少重复代码、更好性能
  5. 使用原则:在真正需要代码复用时使用,不要过度设计