Golang

关注公众号 jb51net

关闭
首页 > 脚本专栏 > Golang > golang泛型Generics

golang泛型Generics的实现

作者:尼克

本文主要介绍了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 给出的指导原则:

✅ 适合使用泛型

// 提取 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
}

❌ 不适合使用泛型

5. 重要陷阱与最佳实践

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

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

核心原则 

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

您可能感兴趣的文章:
阅读全文