💂 在Go中使用泛型函数过滤一个片断的方法

83 阅读1分钟

到目前为止,在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 。正如你在这个例子的输出中所看到的,它适用于stringint 类型的片子,以及任何其他类型的片子。