Go 泛型 filter 功能实现

共 3077字,需浏览 7分钟

 ·

2021-10-17 11:53

还不太清楚Go1.17泛型基本用法的同学可以看下站长之前写的Go泛型系列:提前掌握Go泛型的基本使用[1]正好看此文也可以简单复习一下。今天土拨鼠给大家介绍下泛型过滤(Filter)功能的小短文(参考Implementing a Generic Filter Function in Go[2])。例子也很简单,希望大家能从中有所收获。

功能实现:过滤一下切片中符合条件的元素,并返回

正常情况下的话土拨鼠会简单写一下,一般都是作为一次性使用。

简单版

// filter 过滤掉不符合条件的元素
func filter(items []interface{}) []interface{} {
    filteredItems := []interface{}{}
    for index, value := range items {
        // 过滤掉奇数
        if num.(int)%2 == 0 {
            filteredItems = append(filteredItems, value)
        }
    }
    return filteredItems
}

显然这样写太简单了,一点都不够优雅。条件函数的话这里可以考虑用闭包作为函数参数来稍微优化一下。这样就可以编写各种花样的过滤逻辑咯。

优化版

// filter 过滤掉不符合条件的元素
func filter(items []interface{}, fn func(index int, item interface{}) bool) []interface{} {
    filteredItems := []interface{}{}
    for index, value := range items {
        if fn(index, value) {
            filteredItems = append(filteredItems, value)
        }
    }
    return filteredItems
}

func main() {
    var nums []interface{}
    nums = append(nums, 12345)
    evenNums := filter(nums, func(index int, num interface{}) bool { return num.(int)%2 == 0 })
    
    fmt.Printf("%d", evenNums[0].(int) + 2)
}

约束版

为了使得类型使用更加清晰明了一些,咱们这里使用any类型(可不是随便起的哦,可以参考类型参数提案中any的约束[3])来替代interface{}类型。修改如下:

type any = interface{}

// filter 过滤掉不符合条件的元素
func filter(items []any, fn func(index int, item any) bool) []any {
    filteredItems := []any{}
    for index, value := range items {
        if fn(index, value) {
            filteredItems = append(filteredItems, value)
        }
    }
    return filteredItems
}

这里给大家讲一下什么是约束?约束主要是确保泛型类型的元素始终满足特定的接口类型。根据 Go 的哲学,必须在类型参数声明旁边添加约束。这个demo使用的是any类型等同于interface{},可以接受任意类型的。所以这里的约束作用就由闭包来做了。

func filter[T SomeInterface](items []T )

大家也可以在go2goPlayground[4]进行测试,最终demo如下:

package main

import (
   "fmt"
)

// filter 过滤掉不符合条件的元素
func filter[T any](items []T, fn func(item T "T any") bool) []T {
    filteredItems := []T{}
    for _, value := range items {
        if fn(value) {
            filteredItems = append(filteredItems, value)
        }
    }
    return filteredItems
}

func main() {
    nums := []int{12345}
    evenNums := filter(nums, func(num int) bool { return num%2 == 0 })
    fmt.Println(evenNums)
}

参考资料

[1]

Go泛型系列:提前掌握Go泛型的基本使用: https://polarisxu.studygolang.com/posts/go/generics/generics-basic

[2]

Implementing a Generic Filter Function in Go: https://preslav.me/2021/09/22/implementing-a-generic-filter-function-in-golang/

[3]

类型参数提案中any的约束: https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md#the-constraint

[4]

go2goPlayground: https://go2goplay.golang.org/

[5]

go: don't change the libraries in 1.18: https://github.com/golang/go/issues/48918

[6]

#45955-slices: new package to provide generic slice functions: https://github.com/golang/go/issues/45955

[7]

#48594-proposal: bytes: add Grow, Clip; maybe add bytes/strings Insert, Delete: https://github.com/golang/go/issues/48594





推荐阅读


福利

我为大家整理了一份从入门到进阶的Go学习资料礼包,包含学习建议:入门看什么,进阶看什么。关注公众号 「polarisxu」,回复 ebook 获取;还可以回复「进群」,和数万 Gopher 交流学习。

浏览 23
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报