在Golang中使用泛型实现slice过滤filter()函数 - gosamples


到目前为止,在 Go 中创建函数 filter() 是很困难的,它可以根据谓词的布尔值来过滤任何元素的列表。如果你知道列表的类型,这是有可能的。

func filter(slice []string, f func(string) bool) []string {
    var n []string
    for _, e := range slice {
        if f(e) {
            n = append(n, e)
        }
    }
    return n
}


这种解决方案的主要缺点是,你必须为每个slice类型写一个单独的函数,或者使用interface{}和类型断言。

然而,随着Go 1.18中泛型技术的发布,我们有能力编写类型为参数的函数。
所以现在写一个filter()函数来操作任何类型的slice是没有问题的。

package main

import (
    "fmt"
   
"strings"
)

func filter[T any](slice []T, f func(T) bool) []T {
    var n []T
    for _, e := range slice {
        if f(e) {
            n = append(n, e)
        }
    }
    return n
}

func main() {
    websites := []string{
"http://foo.com", "https://bar.com", "https://gosamples.dev"}
    httpsWebsites := filter(websites, func(v string) bool {
        return strings.HasPrefix(v,
"https://")
    })
    fmt.Println(httpsWebsites)

    numbers := []int{1, 2, 3, 4, 5, 6}
    divisibleBy2 := filter(numbers, func(v int) bool {
        return v % 2 == 0
    })
    fmt.Println(divisibleBy2)
}
输出:
[https:
//bar.com https://gosamples.dev]
[2 4 6]

filter()函数接受一个T类型的slice作为参数。
T类型有any约束,这个约束意味着对slice的类型没有要求--它可以是任何东西。
同一类型的T被用作谓词函数的参数,该函数检查该值是否应该被添加到结果中。
filter()函数的主体很简单。它在slice上进行迭代,并将那些从谓词函数返回真值的元素添加到结果中。
正如你在这个例子的输出中所看到的,它对字符串和int类型的slice都有效,也可以对任何其他类型的slice有效。