到目前为止,在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
}
这种解决方案的主要缺点是,你必须为每个片断类型写一个单独的函数,或者使用interface{} 和类型断言。
然而,随着Go 1.18中泛型技术的发布,我们有能力编写类型为参数的函数。因此,现在编写一个filter() ,对任何类型的分片进行操作的函数是没有问题的。
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 的片断作为参数。T 类型有 any约束,正如你已经从我们之前的泛型教程中知道的,这个约束意味着对分片的类型没有要求--它可以是任何东西。同样的类型T ,作为谓词函数的参数,用于检查该值是否应该被添加到结果中。filter() 函数的主体很简单。它对切片进行迭代,并将那些从谓词函数返回的元素添加到结果中,true 。正如你在这个例子的输出中所看到的,它适用于string 和int 类型的片子,以及任何其他类型的片子。