golang泛型Generics的实现

 更新时间:2026年04月21日 09:28:05   作者:尼克  
本文主要介绍了golang泛型Generics的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

Go 泛型(Generics)自 Go 1.18(2022年3月)引入,允许编写适用于多种类型的通用代码,避免重复实现。以下是核心概念和使用指南:

1. 基本语法

泛型通过 类型参数(Type Parameters) 实现,使用方括号 [] 声明:

// 泛型函数:求最大值
func Max[T constraints.Ordered](slice []T) T {
    if len(slice) == 0 {
        var zero T
        return zero
    }
    max := slice[0]
    for _, v := range slice {
        if v > max {
            max = v
        }
    }
    return max
}
// 使用
ints := []int{1, 3, 2, 5, 4}
floats := []float64{1.1, 3.3, 2.2}
strings := []string{"apple", "banana"}
fmt.Println(Max(ints))    // 5
fmt.Println(Max(floats)) // 3.3
fmt.Println(Max(strings)) // "banana"

2. 类型约束(Constraints)

约束限制类型参数的范围,常用约束来自 golang.org/x/exp/constraints 或标准库:

约束含义适用类型
any任意类型所有类型
comparable可比较(==、!=)支持比较的类型
constraints.Ordered有序(可 <、> 比较)int, float, string 等
interface{ Method() }必须实现指定方法满足接口的类型
// 自定义约束:必须支持 String() 方法
type Stringer interface {
    String() string
}
func PrintAll[T Stringer](items []T) {
    for _, item := range items {
        fmt.Println(item.String())
    }
}

3. 泛型数据结构

泛型最常见的用途是实现通用数据结构,避免为每种类型重复编写代码:

// 泛型栈
type Stack[T any] struct {
    data []T
}
func (s *Stack[T]) Push(item T) {
    s.data = append(s.data, item)
}
func (s *Stack[T]) Pop() (T, error) {
    var zero T
    if len(s.data) == 0 {
        return zero, errors.New("stack is empty")
    }
    item := s.data[len(s.data)-1]
    s.data = s.data[:len(s.data)-1]
    return item, nil
}
// 使用
intStack := Stack[int]{}
strStack := Stack[string]{}

4. 何时使用泛型?(官方建议)

Go 泛型设计者 Ian Lance Taylor 给出的指导原则:

✅ 适合使用泛型

  • 通用数据结构:链表、树、栈等(代码与元素类型无关)
  • 处理内置容器:对 slice、map、channel 进行通用操作(如提取 map 的所有 key)
  • 不同类型实现相同逻辑:如 Len()Swap() 等方法实现完全一致
// 提取 map 的所有 key(与 value 类型无关)
func MapKeys[Key comparable, Val any](m map[Key]Val) []Key {
    s := make([]Key, 0, len(m))
    for k := range m {
        s = append(s, k)
    }
    return s
}

❌ 不适合使用泛型

  • 仅调用方法时:直接用 interface(如 io.Reader),不要写成 func Read[T io.Reader](r T)
  • 不同实现逻辑时:用接口+多态,而非泛型(如文件读取 vs 随机数生成器的 Read
  • 为了性能优化:泛型实例化后的代码通常不会比 interface 更快

5. 重要陷阱与最佳实践

避免指针类型作为类型参数

// ❌ 错误:T 是类型参数,不是指针,无法解引用
func Set[T *int|*uint](ptr T) { *ptr = 1 }
// ✅ 正确:明确使用 *T
func Set[T int|uint](ptr *T) { *ptr = 1 }

核心原则 

  • 从写函数开始,发现重复代码时再引入类型参数,不要先定义约束
  • 优先用函数而非方法:传入 func(T, T) bool 比较函数,比要求类型实现 Compare() 方法更灵活
  • 明确使用 *T、[]T、map[K]V,不要让 T 代表指针、slice 或 map 本身
  • 不要过度泛型化:如果接口(interface)能解决问题,就不要用泛型

6. 类型集合(Type Sets)

Go 1.18+ 支持使用 | 定义类型集合:

// 只接受 int 或 string
func Process[T int | string](val T) {
    fmt.Println(val)
}
// 结合接口约束
type Number interface {
    ~int | ~int64 | ~float64  // ~ 表示底层类型
}
func Sum[T Number](vals []T) T {
    var sum T
    for _, v := range vals {
        sum += v
    }
    return sum
}

~int 表示底层类型为 int 的所有类型(包括 type MyInt int 这种自定义类型)。

总结:Go 泛型的设计哲学是 "用代码写程序,而不是用类型定义写程序"。当你发现自己在复制粘贴几乎相同的代码、只改类型时,就是引入泛型的最佳时机。但 Go 的 interface 机制已经非常强大,如果只是调用方法,优先使用 interface 而非泛型。

到此这篇关于golang泛型Generics的实现的文章就介绍到这了,更多相关golang泛型Generics内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • go程序测试CPU占用率统计ps vs top两种不同方式对比

    go程序测试CPU占用率统计ps vs top两种不同方式对比

    这篇文章主要为大家介绍了go程序测试CPU占用率统计ps vs top两种不同方式对比,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • Go gorilla securecookie库的安装使用详解

    Go gorilla securecookie库的安装使用详解

    这篇文章主要介绍了Go gorilla securecookie库的安装使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • Golang中的Interface详解

    Golang中的Interface详解

    本文详细讲解了Golang中的Interface,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • Go语言中的原子操作使用详解

    Go语言中的原子操作使用详解

    这篇文章主要介绍了Go语言中的原子操作使用详解的相关资料,需要的朋友可以参考下
    2023-08-08
  • go实现grpc四种数据流模式

    go实现grpc四种数据流模式

    这篇文章主要为大家介绍了go实现grpc四种数据流模式,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2022-04-04
  •  Go 语言实现 HTTP 文件上传和下载

     Go 语言实现 HTTP 文件上传和下载

    这篇文章主要介绍了Go语言实现HTTP文件上传和下载,文章围绕主题展开详细的内容戒杀,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-09-09
  • 手把手教你如何在Goland中创建和运行项目

    手把手教你如何在Goland中创建和运行项目

    欢迎来到本指南!我们将手把手地教您在Goland中如何创建、配置并运行项目,通过简单的步骤,您将迅速上手这款强大的集成开发环境(IDE),轻松实现您的编程梦想,让我们一起开启这段精彩的旅程吧!
    2024-02-02
  • Go语言实现单端口转发到多个端口

    Go语言实现单端口转发到多个端口

    这篇文章主要为大家详细介绍了Go语言实现单端口转发到多个端口,文中的示例代码讲解详细,具有一定的参考价值,对大家的学习或工作有一定的帮助,需要的小伙伴可以了解下
    2024-02-02
  • go 生成器模式的具体使用

    go 生成器模式的具体使用

    生成器是一种创建型设计模式,使你能够分步骤创建复杂对象,本文主要介绍了go生成器模式的具体使用,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01
  • 详解Go语言RESTful JSON API创建

    详解Go语言RESTful JSON API创建

    这篇文章主要介绍了详解Go语言RESTful JSON API创建,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05

最新评论