Go 泛型

泛型的基本语法

Go 1.18 引入泛型,用类型参数(方括号)和类型约束(接口 + 类型集)编写通用代码:

// 泛型函数:交换两个变量
func Swap[T any](a, b *T) {
    *a, *b = *b, *a
}

// 泛型类型:栈
type Stack[T any] []T

func (s *Stack[T]) Push(v T) { *s = append(*s, v) }

内置约束 any(任意类型)和 comparable(可比较类型);自定义约束用类型集:

type Number interface {
    int | int64 | float64   // 类型集:只接受这些类型
}

func Add[T Number](a, b T) T { return a + b }

Add(3, 5)        // OK
Add(3.14, 2.71)  // OK

主要应用场景

1. 集合操作

func Filter[T any](s []T, f func(T) bool) []T {
    var result []T
    for _, v := range s {
        if f(v) { result = append(result, v) }
    }
    return result
}

func Map[T, U any](s []T, f func(T) U) []U {
    result := make([]U, len(s))
    for i, v := range s { result[i] = f(v) }
    return result
}

even := Filter([]int{1, 2, 3, 4, 5}, func(n int) bool { return n%2 == 0 })
squares := Map([]int{1, 2, 3}, func(n int) int { return n * n })

2. 通用数据结构

type Cache[K comparable, V any] struct {
    data map[K]V
}

func (c *Cache[K, V]) Get(key K) (V, bool) {
    v, ok := c.data[key]
    return v, ok
}

3. 泛型排序(需要约束支持比较)

func SortSlice[T interface{ ~int | ~float64 | ~string }](s []T) {
    sort.Slice(s, func(i, j int) bool { return s[i] < s[j] })
}

注意:Go 泛型目前没有 < 运算符约束,想对任意可比较类型排序需要自定义约束或用 cmp.Ordered(Go 1.21+):

import "cmp"
func SortAny[T cmp.Ordered](s []T) { sort.Slice(s, func(i, j int) bool { return s[i] < s[j] }) }

泛型 vs interface{}(反射)

// 传统方式:interface{} + 类型断言,运行期才检查,性能差
func PrintAll(vals []interface{}) { ... }

// 泛型:编译期类型检查,无反射开销
func PrintAll[T any](vals []T) { ... }

泛型的性能接近手写特化代码(编译器按类型参数实例化),同时保留静态类型安全。

注意事项与最佳实践

  • 优先用于:多类型容器、通用算法(过滤/映射/排序)、通用数据结构;
  • 避免滥用:单一类型、简单场景用泛型只会增加阅读负担;
  • 编译时间:泛型会略微增加编译时间(约 15–18%),Go 1.23+ 有改善;
  • 约束用最小化:约束越宽越好用,能用 comparable 就别自定义更严的约束;
  • 工具链:需要 Go ≥ 1.18,IDE 支持(GoLand 2022.1+ / VSCode 新版)。

总结

泛型是 Go 1.18 以来最大的语言能力升级:编译期类型安全 + 复用 + 高性能。集合操作、通用数据结构、算法模板是它的主战场;配合 Go 1.21 的 cmp.Orderedslices/maps 标准包,日常写泛型代码已经非常顺手。

滚动至顶部