跳转到主要内容
模块 10 · 第 3 课(共 5)课程中的48/50~15 min
模块课程(3/5)

泛型(Go 1.18+)

自 Go 1.18(2022 年 3 月)起,类型参数可用:函数和类型可以通过类型进行参数化。它们允许您编写 Map、Filter、Set[T]、LinkedList[T],无需重复代码,也无需 interface{} + 运行时类型断言。

通用函数:语法

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

doubled := Map([]int{1, 2, 3}, func(n int) int { return n * 2 })
// doubled is []int{2, 4, 6}

三个新元素:

  • [T, U any] 名称之后:声明类型参数及其约束。
  • any = 接受任何类型的约束(自 Go 1.18 起为 interface{} 的别名)。
  • 推断:调用 Map([]int{...}, ...) 您不必编写 Map[int, int](...):编译器推断 T=int, U=int。

有时推理是不够的(例如,没有 T 参数的构造函数),需要显式实例化:New[*Server]()。

内置约束

约束意义
any任何类型(== interface{})。
comparable具有 == 和 != 的类型:数字、字符串、布尔值、指针、通道、可比较的数组/结构。

comparable 允许相等,但不允许 < 或 >。

Go
func Index[T comparable](s []T, x T) int {
    for i, v := range s {
        if v == x { return i }
    }
    return -1
}

对于 </> 您需要一个自定义约束。

自定义约束:类型联合

约束是一个带有“类型元素”子句的接口:

Go
type Ordered interface {
    ~int | ~int64 | ~float64 | ~string
}

func Min[T Ordered](a, b T) T {
    if a < b { return a }
    return b
}
  • | = union:接受任何列出的类型。
  • ~int =“int 或定义为 type X int 的任何类型”(具有相同的基础类型)。没有 ~,只有精确的 int。

约束还可以混合方法和类型元素:

Go
type Stringable interface {
    ~string
    Len() int
}

通用类型

不仅是函数:结构和接口也可以有类型参数。

Go
type Set[T comparable] struct {
    m map[T]struct{}
}

func NewSet[T comparable]() *Set[T] {
    return &Set[T]{m: make(map[T]struct{})}
}

func (s *Set[T]) Add(v T) { s.m[v] = struct{}{} }
func (s *Set[T]) Has(v T) bool { _, ok := s.m[v]; return ok }

s := NewSet[string]()
s.Add("ada")

方法不能添加超出类型参数的类型参数:func (s *Set[T]) MapTo[U any](...) 不编译(有意设计限制)。

何时使用泛型

是当:

  • 对于几种类型(集合、算法、像 Map/Filter/Reduce 这样的帮助器),逻辑确实相同。
  • 另一种方法是复制代码或使用 interface{} + 类型断言(失去类型安全)。

不,当:

  • 具有一两个方法的接口就足够了并且更具可读性(io.Reader,fmt.Stringer)。
  • 你正在参数化“因为你可以”:单个用例 → 制作它的具体版本。

练习

锻炼#go.m10.l3.e1
尝试:0加载中...

定义通用函数 Min[T Ordered](a, b T) T che ritorna il secondary usando l'operatore <. Il 约束 Ordered è già fornito。

正在加载编辑器...

3 次尝试后可用的解决方案

锻炼#go.m10.l3.e2
尝试:0加载中...

实现 Map[T, U any](s []T, f func(T) U) []U:应用新切片中的所有元素和恢复。

正在加载编辑器...

3 次尝试后可用的解决方案

Quiz#go.m10.l3.e3
准备好

Quale 约束内置 Consente l'operatore == ma NON l'operatore <?

Go
func Index[T ???](s []T, x T) int { ... }
答案选项