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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • golang游戏等资源压缩包创建和操作方法

    golang游戏等资源压缩包创建和操作方法

    这篇文章主要介绍了golang游戏等资源压缩包创建和操作,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-08-08
  • Go语言实现猜数字小游戏

    Go语言实现猜数字小游戏

    这篇文章主要为大家详细介绍了Go语言实现猜数字小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-10-10
  • Go系列教程之反射的用法

    Go系列教程之反射的用法

    这篇文章主要介绍了Go系列教程之反射的用法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-01-01
  • go语言使用scp的方法实例分析

    go语言使用scp的方法实例分析

    这篇文章主要介绍了go语言使用scp的方法,实例分析了go语言调用scp命令的使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-03-03
  • GO语言中接口和接口型函数的具体使用

    GO语言中接口和接口型函数的具体使用

    本文主要介绍了GO语言中接口和接口型函数的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • Go语言中切片展开操作符的实现示例

    Go语言中切片展开操作符的实现示例

    在Go语言编程中,我们经常会遇到处理多维切片数据的场景,今天我们来深入探讨一个非常实用但容易被忽视的语法特性-切片展开操作符,感兴趣的可以了解一下
    2025-10-10
  • Golang使用Apache PLC4X连接modbus的示例代码

    Golang使用Apache PLC4X连接modbus的示例代码

    Modbus是一种串行通信协议,是Modicon公司于1979年为使用可编程逻辑控制器(PLC)通信而发表,这篇文章主要介绍了Golang使用Apache PLC4X连接modbus的示例代码,需要的朋友可以参考下
    2024-07-07
  • 教你一招完美解决vscode安装go插件失败问题

    教你一招完美解决vscode安装go插件失败问题

    VSCode是我们开发go程序的常用工具,但是安装VSCode成功后,创建一个.go文件居然提示错误了,所以下面下面这篇文章主要给大家介绍了如何通过一招完美解决vscode安装go插件失败问题的相关资料,需要的朋友可以参考下
    2022-07-07
  • Go中sync.Mutex 加锁失效的问题解决

    Go中sync.Mutex 加锁失效的问题解决

    sync.Mutex是Go标准库中常用的一个排外锁,本文主要介绍了Go中sync.Mutex 加锁失效的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-08-08
  • gorm update传入struct对象,零值字段不更新的解决方案

    gorm update传入struct对象,零值字段不更新的解决方案

    这篇文章主要介绍了gorm update传入struct对象,零值字段不更新的解决方案,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04

最新评论