Go每日一库之173:Pie (高性能、类型安全的slice操作库)

发布时间 2023-09-29 21:15:29作者: 阿瑞娜

在Go语言中,对slice和map是我们最常用的数据结构。比如,计算两个切片的交集、差集;判断切片中的元素是否都满足某个条件的等。我推荐大家使用这个包:[elliotchance/pie](https://github.com/elliotchance/pie)

该包封装了对切片和map的常用操作,能满足工作中的大部分需求。比如计算切片的交集、差集;对切片中元素按条件过滤的Filter函数;对切片中元素进行数据转换的Each、Map函数等。

同时具有高性能类型安全的特点。实现中对各函数的参数都做了类型的限制。比如Average函数就只能对整型和浮点型参数有效。

使用pie包的要求:

pie v2版本需要Go 1.18+。Go1.17及以下版本需要使用v1版本。

pie包的目标:

  • 类型安全:无论是在v1版本还是v2版本的泛型中,都对类型做了限制,所以不会遇到运行时类型错误。
  • 高性能:该库需要跟原生的Go实现一样快,否则该库封装就没有意义。
  • Nil安全:该库的所有函数都能接收nil参数,并将其视为空切片,而不会引起panic。
  • 对原切片无副作用:所有的函数对传入的切片参数都不会做修改。

使用示例

go 版本在1.18及以上,会使用pie/v2包,该包使用的是泛型。

package main

import (
    "fmt"
    "strings"

    "github.com/elliotchance/pie/v2"
)

func main() {

    name := pie.Of([]string{"Bob", "Sally", "John", "Jane"}).
    FilterNot(func(name string) bool {
        return strings.HasPrefix(name, "J")
    }).
    Map(strings.ToUpper).
    Last()

    fmt.Println(name) // "SALLY"
}

go1.17及以下版本需要使用pie/v1包。因为在1.17之前go还不支持泛型,所以函数只能针对特定类型的切片。在该v1包中,pie实际上是定义了一组类型切片。比如,代表string切片的pie.Strings类型。代表float64切片的pie.Float64s类型。那么该版本在使用时需要先定义切片的类型。如下:

package main

import (
    "fmt"
    "strings"

    "github.com/elliotchance/pie/pie"
)

func main() {
    var names pie.Strings //看pie的源码Strings的底层类型是[]string
    names = []string{"Bob", "Sally", "John", "Jane"}

    name := names.FilterNot(func(name string) bool {
        return strings.HasPrefix(name, "J")
    }).
    Map(strings.ToUpper).
    Last()

    fmt.Println(name) // "SALLY"
}

pie包支持的功能:

  • 切片中的元素是否全部或任意一个满足指定的条件。
  • All函数:判断切片中的元素是否都满足指定的条件。
  • Any函数:判断切片中的元素只要有1个满足指定条件即可。
  • 对切片元素进行排序功能。
  • AreSorted函数:判断切片是否是有序的
  • Sort函数:对切片元素进行排序。
  • SortStableUsing函数:使用指定的条件对切片进行排序,并且具有稳定性。
  • SortUsing函数
  • 对切片中的元素去重。
  • 判断切片中的元素是否不重复的AreUnique函数、去重函数Unique
  • 对切片进行前、后截取。
  • Bottom函数:取切片后n个元素
  • Top函数:取切片前n个元素
  • DropTop函数:丢掉切片的前n个元素,并返回剩余的元素切片
  • 两个或多个切片之间的集合运算
  • Diff函数:计算两个切片中的差集
  • Intersect函数:计算两个或多个切片的交集
  • 切片元素进行算数运算功能(只针对Integer和float类型的切片有效)。
  • Max函数:返回切片中的最大元素
  • Min函数:返回切片中的最小元素
  • Product函数:对切片所有元素进行乘积运算
  • Sum函数:对切片中所有元素进行求和运算
  • Average函数:求所有元素的平均值
  • 对切片中的元素进行数据转换功能:Each、Map、Filter、Flat、Reducer
  • 针对map的操作:
  • Keys函数:获取map的所有键
  • Values函数:获取map的所有值

更多、更详细的功能请参考pie包的源码。

总结

pie包几乎把slice经常用到的功能都做了封装,可谓是给开发者节省了大量时间。同时,v2包利用了泛型中的类型限制,保证了类型的安全。在性能方面,该包采用了很多策略:在已知切片长度的情况下尽可能给slice分配固定长度的内存,减少在使用append时内存申请的次数;使用切片截取的形式,避免内存再次分配。