文章

泛型

泛型(Go 1.18+)

基本语法

// 泛型函数:类型参数在函数名后用方括号声明
func Max[T int | float64 | string](a, b T) T {
    if a > b {
        return a
    }
    return b
}

// 调用
Max(3, 5)              // 类型推断:T=int
Max(3.14, 2.71)        // 类型推断:T=float64
Max[int](3, 5)         // 显式指定
Max("hello", "world")  // T=string

类型约束

内置约束 comparable

// comparable:支持 == 和 != 的类型
func Contains[T comparable](slice []T, target T) bool {
    for _, v := range slice {
        if v == target {
            return true
        }
    }
    return false
}

Contains([]int{1, 2, 3}, 2)           // true
Contains([]string{"a", "b"}, "c")     // false

自定义约束

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

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

Sum([]int{1, 2, 3})          // 6
Sum([]float64{1.1, 2.2})     // 3.3

~ 符号(底层类型约束)

// ~ 表示包含底层类型为 T 的所有自定义类型
type Number interface {
    ~int | ~int64 | ~float32 | ~float64
}

type Celsius float64  // 底层类型是 float64
type Score int        // 底层类型是 int

func Double[T Number](v T) T {
    return v * 2
}

Double(Celsius(36.5))  // ✓ 有 ~ 才能用
Double(Score(95))      // ✓ 有 ~ 才能用

constraints 包(golang.org/x/exp/constraints)

import "golang.org/x/exp/constraints"

// Ordered:所有支持 < > <= >= 的类型
func Max[T constraints.Ordered](a, b T) T {
    if a > b {
        return a
    }
    return b
}

// Signed / Unsigned / Integer / Float / Ordered
// 这些约束在 Go 1.21+ 已移入标准库 cmp 包

泛型数据结构

泛型 Stack

type Stack[T any] struct {
    items []T
}

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

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

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

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

func (s *Stack[T]) Len() int {
    return len(s.items)
}

// 使用
intStack := NewStack[int]()
intStack.Push(1)
intStack.Push(2)
v, _ := intStack.Pop()  // 2

strStack := NewStack[string]()
strStack.Push("hello")

泛型 Set

type Set[T comparable] struct {
    items map[T]struct{}
}

func NewSet[T comparable](items ...T) *Set[T] {
    s := &Set[T]{items: make(map[T]struct{})}
    for _, item := range items {
        s.items[item] = struct{}{}
    }
    return s
}

func (s *Set[T]) Add(item T) {
    s.items[item] = struct{}{}
}

func (s *Set[T]) Remove(item T) {
    delete(s.items, item)
}

func (s *Set[T]) Contains(item T) bool {
    _, ok := s.items[item]
    return ok
}

func (s *Set[T]) Union(other *Set[T]) *Set[T] {
    result := NewSet[T]()
    for k := range s.items {
        result.Add(k)
    }
    for k := range other.items {
        result.Add(k)
    }
    return result
}

func (s *Set[T]) Intersect(other *Set[T]) *Set[T] {
    result := NewSet[T]()
    for k := range s.items {
        if other.Contains(k) {
            result.Add(k)
        }
    }
    return result
}

func (s *Set[T]) ToSlice() []T {
    result := make([]T, 0, len(s.items))
    for k := range s.items {
        result = append(result, k)
    }
    return result
}

泛型 Map 工具函数

// Map:对 slice 每个元素应用函数
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
}

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

// Reduce:归约
func Reduce[T, U any](slice []T, initial U, fn func(U, T) U) U {
    result := initial
    for _, v := range slice {
        result = fn(result, v)
    }
    return result
}

// 使用
nums := []int{1, 2, 3, 4, 5}

// 每个元素 *2
doubled := Map(nums, func(n int) int { return n * 2 })
// [2, 4, 6, 8, 10]

// 过滤偶数
evens := Filter(nums, func(n int) bool { return n%2 == 0 })
// [2, 4]

// 求和
sum := Reduce(nums, 0, func(acc, n int) int { return acc + n })
// 15

// 类型转换
strs := Map(nums, strconv.Itoa)
// ["1", "2", "3", "4", "5"]

泛型 Pair / Tuple

type Pair[A, B any] struct {
    First  A
    Second B
}

func NewPair[A, B any](a A, b B) Pair[A, B] {
    return Pair[A, B]{First: a, Second: b}
}

// 使用
p := NewPair("小徐", 28)
// p.First = "小徐"
// p.Second = 28

泛型 Cache

type Cache[K comparable, V any] struct {
    mu      sync.RWMutex
    items   map[K]V
    ttl     time.Duration
    expires map[K]time.Time
}

func NewCache[K comparable, V any](ttl time.Duration) *Cache[K, V] {
    return &Cache[K, V]{
        items:   make(map[K]V),
        expires: make(map[K]time.Time),
        ttl:     ttl,
    }
}

func (c *Cache[K, V]) Set(key K, value V) {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.items[key] = value
    c.expires[key] = time.Now().Add(c.ttl)
}

func (c *Cache[K, V]) Get(key K) (V, bool) {
    c.mu.RLock()
    defer c.mu.RUnlock()

    var zero V

    // 检查过期
    if exp, ok := c.expires[key]; ok {
        if time.Now().After(exp) {
            return zero, false
        }
    }

    val, ok := c.items[key]
    return val, ok
}

// 使用
userCache := NewCache[string, *User](5 * time.Minute)
userCache.Set("user:1", &User{Name: "小徐"})
user, ok := userCache.Get("user:1")

泛型 vs 接口 vs 代码生成

方案类型安全性能可读性复杂度
泛型✓ 编译时
interface{}✗ 运行时中(有装箱)
接口多态✓ 编译时
代码生成✓ 编译时最高高(需要生成步骤)
场景推荐
通用数据结构(Stack/Queue/Set/Cache)泛型
通用工具函数(Map/Filter/Reduce)泛型
需要多种类型支持(如 sort.Slice)泛型
不同类型有不同实现逻辑接口
需要极致性能代码生成
类型安全不重要的简单脚本interface{}

泛型限制

限制说明替代方案
不能有泛型方法只有函数和类型可以泛型,方法不行泛型函数包装
不能在类型约束中引用自身type T interface{ ~T } 不合法使用具体类型
不能用泛型类型做类型断言v.(T) 中 T 必须是具体类型type switch
零值不能直接获取不能写 var zero T(T 可以是 any)var zero T 实际可以,但要注意 nil
不能直接做算术运算约束中没有 + 运算符自定义约束接口
// ❌ 方法不能有自己的类型参数
type Container struct{}
func (c Container) Get[T any](key string) T { ... }  // 编译错误

// ✓ 用泛型函数包装
type Container struct{}
func Get[T any](c Container, key string) T { ... }

slices 和 maps 标准库(Go 1.21+)

import "slices"
import "maps"

// slices 包:泛型 slice 操作
s := []int{3, 1, 4, 1, 5, 9, 2, 6}

slices.Sort(s)                        // [1, 1, 2, 3, 4, 5, 6, 9]
slices.SortFunc(s, func(a, b int) int { return b - a })  // 降序
slices.Contains(s, 5)                  // true
slices.Index(s, 4)                     // 索引
slices.Reverse(s)                      // 原地反转
slices.Max(s)                          // 最大值
slices.Min(s)                          // 最小值
slices.BinarySearch(s, 5)              // 二分查找

// maps 包:泛型 map 操作
m := map[string]int{"a": 1, "b": 2, "c": 3}

keys := maps.Keys(m)                   // []string{"a", "b", "c"}(顺序随机)
values := maps.Values(m)               // []int{1, 2, 3}
maps.Copy(m, map[string]int{"d": 4})   // 合并
maps.DeleteFunc(m, func(k string, v int) bool { return v < 2 })  // 条件删除
m2 := maps.Clone(m)                    // 浅拷贝
maps.Equal(m, m2)                      // true

cmp 标准库(Go 1.21+)

import "cmp"

// cmp.Compare:返回 -1, 0, 1
cmp.Compare(1, 2)    // -1
cmp.Compare(2, 2)    // 0
cmp.Compare(3, 2)    // 1

// cmp.Or:返回第一个非零值
name := cmp.Or(inputName, "default")  // 如果 inputName 为 "",返回 "default"