Skip to content

泛型

Go 1.18 引入了泛型(Generics)支持,这是 Go 语言的一个重要里程碑。

泛型基础

类型参数

go
// 泛型函数
func Print[T any](v T) {
    fmt.Println(v)
}

// 使用
Print(42)        // 42
Print("hello")    // hello
Print(3.14)       // 3.14

类型约束

go
// 定义类型约束
type Number interface {
    int | float64
}

// 使用约束
func Add[T Number](a, b T) T {
    return a + b
}

// 使用
sum1 := Add(1, 2)        // 3
sum2 := Add(1.5, 2.5)    // 4.0
// sum3 := Add("a", "b")  // 编译错误

类型参数语法

函数泛型

go
// 单个类型参数
func Identity[T any](v T) T {
    return v
}

// 多个类型参数
func Map[K comparable, V any](m map[K]V, key K) (V, bool) {
    v, ok := m[key]
    return v, ok
}

// 使用
result := Identity(42)
value, ok := Map(map[string]int{"a": 1}, "a")

结构体泛型

go
// 泛型结构体
type Stack[T any] struct {
    items []T
}

func (s *Stack[T]) Push(item T) {
    s.items = append(s.items, item)
}

func (s *Stack[T]) Pop() (T, bool) {
    if len(s.items) == 0 {
        var zero T
        return zero, false
    }
    item := s.items[len(s.items)-1]
    s.items = s.items[:len(s.items)-1]
    return item, true
}

// 使用
stack := &Stack[int]{}
stack.Push(1)
stack.Push(2)
item, _ := stack.Pop()

接口泛型

go
// 泛型接口
type Container[T any] interface {
    Add(item T)
    Get(index int) T
    Size() int
}

// 实现接口
type List[T any] struct {
    items []T
}

func (l *List[T]) Add(item T) {
    l.items = append(l.items, item)
}

func (l *List[T]) Get(index int) T {
    return l.items[index]
}

func (l *List[T]) Size() int {
    return len(l.items)
}

类型约束详解

联合类型

go
// 使用 | 定义联合类型
type Integer interface {
    int | int8 | int16 | int32 | int64
}

type Float interface {
    float32 | float64
}

type Number interface {
    Integer | Float
}

近似约束

go
// ~ 表示底层类型
type Int interface {
    ~int | ~int8 | ~int16 | ~int32 | ~int64
}

type MyInt int

// MyInt 满足 Int 约束(因为底层类型是 int)
func Process[T Int](v T) T {
    return v
}

var x MyInt = 42
Process(x)  // OK

方法约束

go
// 约束可以包含方法
type Stringer interface {
    String() string
}

func Print[T Stringer](v T) {
    fmt.Println(v.String())
}

comparable 约束

go
// comparable 是内置约束,用于可比较的类型
func Find[T comparable](slice []T, item T) int {
    for i, v := range slice {
        if v == item {
            return i
        }
    }
    return -1
}

实际应用

通用容器

go
// 队列
type Queue[T any] struct {
    items []T
}

func (q *Queue[T]) Enqueue(item T) {
    q.items = append(q.items, item)
}

func (q *Queue[T]) Dequeue() (T, bool) {
    if len(q.items) == 0 {
        var zero T
        return zero, false
    }
    item := q.items[0]
    q.items = q.items[1:]
    return item, true
}

工具函数

go
// 反转切片
func Reverse[T any](slice []T) []T {
    result := make([]T, len(slice))
    for i, v := range slice {
        result[len(slice)-1-i] = v
    }
    return result
}

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

// 过滤
func Filter[T any](slice []T, predicate func(T) bool) []T {
    result := []T{}
    for _, v := range slice {
        if predicate(v) {
            result = append(result, v)
        }
    }
    return result
}

类型安全的 Map 操作

go
// Map 函数(转换元素)
func Map[T, U any](slice []T, fn func(T) U) []U {
    result := make([]U, len(slice))
    for i, v := range slice {
        result[i] = fn(v)
    }
    return result
}

// 使用
numbers := []int{1, 2, 3, 4, 5}
doubled := Map(numbers, func(n int) int {
    return n * 2
})
strings := Map(numbers, func(n int) string {
    return fmt.Sprintf("%d", n)
})

约束组合

go
// 组合多个约束
type Numeric interface {
    ~int | ~float64
}

type ComparableNumeric interface {
    Numeric
    comparable
}

func Max[T ComparableNumeric](a, b T) T {
    if a > b {
        return a
    }
    return b
}

类型推断

Go 编译器可以自动推断类型参数:

go
// 可以省略类型参数
Print(42)              // 推断为 Print[int]
Print[string]("hello")  // 显式指定

// 多个类型参数
func Pair[T, U any](t T, u U) (T, U) {
    return t, u
}

a, b := Pair(1, "hello")  // 推断为 Pair[int, string]

完整示例

go
package main

import "fmt"

// 泛型栈
type Stack[T any] struct {
    items []T
}

func NewStack[T any]() *Stack[T] {
    return &Stack[T]{items: []T{}}
}

func (s *Stack[T]) Push(item T) {
    s.items = append(s.items, item)
}

func (s *Stack[T]) Pop() (T, bool) {
    if len(s.items) == 0 {
        var zero T
        return zero, false
    }
    item := s.items[len(s.items)-1]
    s.items = s.items[:len(s.items)-1]
    return item, true
}

// 泛型函数
func Max[T comparable](a, b T) T {
    if a > b {
        return a
    }
    return b
}

// 类型约束
type Numeric interface {
    ~int | ~float64
}

func Sum[T Numeric](numbers []T) T {
    var sum T
    for _, n := range numbers {
        sum += n
    }
    return sum
}

func main() {
    // 使用泛型栈
    intStack := NewStack[int]()
    intStack.Push(1)
    intStack.Push(2)
    item, _ := intStack.Pop()
    fmt.Println(item)  // 2
    
    // 使用泛型函数
    maxInt := Max(10, 20)
    fmt.Println(maxInt)  // 20
    
    // 使用类型约束
    numbers := []int{1, 2, 3, 4, 5}
    sum := Sum(numbers)
    fmt.Println(sum)  // 15
}

最佳实践

  1. 从具体开始:先写具体类型,再抽象为泛型
  2. 保持简单:不要过度使用泛型
  3. 使用有意义的约束:约束应该表达清晰的意图
  4. 利用类型推断:让编译器推断类型参数
  5. 文档化约束:为复杂的约束添加注释

限制

  1. 方法不能有类型参数:只有函数和类型可以有类型参数
  2. 不能使用类型断言到类型参数:需要使用类型开关
  3. 某些操作受限:不是所有类型都支持所有操作

下一步

接下来我们将学习:

基于 VitePress 构建