在Go中使用泛型实现最小值和最大值函数 - gosamples


从slice中获取最小值和最大值是开发人员在日常编码中编写的一些最简单的函数。
问题是,当你想从int和float64s这个slice中获取最小值或最大值时,1.18版本以前,你不得不为每个slice类型写两个函数。
然而,从1.18版本开始,Go引入了备受期待的泛型函数,现在你可以编写单一的min()和max()函数,适用于任何有序类型。

package main

import (
    "fmt"

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

func max[T constraints.Ordered](s []T) T {
    if len(s) == 0 {
        var zero T
        return zero
    }
    m := s[0]
    for _, v := range s {
        if m < v {
            m = v
        }
    }
    return m
}

func min[T constraints.Ordered](s []T) T {
    if len(s) == 0 {
        var zero T
        return zero
    }
    m := s[0]
    for _, v := range s {
        if m > v {
            m = v
        }
    }
    return m
}

func main() {
    fmt.Println(min([]int{10, 2, 4, 1, 6, 8, 2}))
    fmt.Println(max([]float64{3.2, 5.1, 6.2, 7.6, 8.2, 1.5, 4.8}))
}

泛型函数需要类型参数,它们描述了给定函数所允许的类型,并提供了在函数主体中使用的类型标签。正如你在例子中看到的,它们被声明在函数名称后面的方括号中。

func name[TypeLabel Constraints](...) {
    ...
}

在min()和max()函数中,我们声明了一个带constraints.Ordered的类型参数T。
它保证这些函数只对支持运算符<, <=, >=, >的slice类型工作。
其余的函数是非常直接的:它们接受一个T类型的slice作为参数,如果slice的大小为0,则返回一个给定类型的零值,并在一个循环中找到slice的最小或最大。结果是,它们返回一个单一的T类型的最小或最大值。

从上面的例子中,我们得到以下输出。

1
8.2


由于泛型的存在,我们可以在Go中做出以前不可能做到的事情,这真的很令人兴奋。我们确信,这一功能将提高任何Go项目的代码质量。