在Go中使用泛型函数获取最小值和最大值的方法

1,100 阅读2分钟

从切片中获取最小值和最大值是开发人员在日常编码中编写的一些最简单的函数。问题是,当你想从intfloat64 分片中获取最小值或最大值时,直到现在,你还必须为每个切片类型写两个函数。然而,从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() 函数中,我们声明了一个类型参数T ,并带有 constraints.Ordered的约束。它保证这些函数只对支持运算符<,<=,>=,> 的片断类型工作。其余的函数是非常直接的。它们接受一个类型为T 的片断作为参数,如果片断的大小为0,则返回一个给定类型的零值,并在一个循环中找到片断的最小或最大。因此,它们返回一个单一的最小或最大值,类型为T

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

1
8.2

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