golang函数式编程工具集插件库fp-go的使用
fp-go: Golang函数式编程工具集插件库使用指南
fp-go是一个基于Golang 1.18+泛型实现的函数式编程辅助工具库。
安装
需要Go 1.18+版本:
go get github.com/repeale/fp-go
主要特性
柯里化(Currying)
默认支持柯里化,数据最后传入:
func isPositive(x int) bool {
return x > 0
}
func main() {
filterPositive := fp.Filter(isPositive)
numbers := []int{1, 2, 3, 4, 5}
positives := filterPositive(numbers)
}
变体(Variations)
变体允许你在回调函数中获取不同的参数,只获取真正需要的参数。
默认变体
只获取当前元素:
fp.Map[int, string](func(x int) { ... })
带索引变体
获取当前元素和索引:
fp.MapWithIndex[int, string](func(x int, i int) { ... })
带切片变体
获取当前元素、索引和整个切片:
fp.MapWithSlice[int, string](func(x int, i int, xs: []int) { ... })
辅助函数
Every
判断数组中的所有元素是否满足指定条件。
变体: EveryWithIndex
和 EveryWithSlice
fp.Every(func(x int) bool { return x > 0 })([]int{1, 2, 3})
// => true
Filter
返回数组中满足回调函数条件的元素。
变体: FilterWithIndex
和 FilterWithSlice
fp.Filter(func(x int) bool { return x > 0 })([]int{-1, 2, -3, 4})
// => []int{2, 4}
Flat
将多维数组扁平化为一维数组:
fp.Flat([][]int{{1, 2}, {3, 4}})
// => []int{1, 2, 3, 4}
FlatMap
对数组每个元素调用回调函数,然后将结果扁平化。
变体: FlatMapWithIndex
和 FlatMapWithSlice
fp.FlatMap(func(x int) []int { return []int{x, x} })([]int{1, 2})
// => []int{1, 1, 2, 2}
Map
对数组每个元素调用回调函数,返回结果数组。
变体: MapWithIndex
和 MapWithSlice
fp.Map(func(x int64) string {
return strconv.FormatInt(x, 10)
})([]int64{1, 2, 3})
// => []string{"1", "2", "3"}
Reduce
对数组每个元素调用回调函数,累积结果。
变体: ReduceWithIndex
和 ReduceWithSlice
fp.Reduce(func(acc int, curr int) int { return acc + curr }, 0)([]int{1, 2, 3})
// => 6
Some
判断数组中是否有元素满足回调函数条件。
变体: SomeWithIndex
和 SomeWithSlice
fp.Some(func(x int) bool { return x < 0 })([]int{1, 2, 3})
// => false
Compose
从右到左组合函数。
变体: Compose2
到 Compose16
表示要组合的函数数量。
func isPositive(x int) bool {
return x > 0
}
func sumTwo(x int) int {
return x + 2
}
Compose2(fp.Filter(isPositive), fp.Map(sumTwo))([]int{1, 2, 3, -1})
// => []int{3, 4, 5, 1}
Pipe
从左到右组合函数。
变体: Pipe2
到 Pipe16
表示要组合的函数数量。
func isPositive(x int) bool {
return x > 0
}
func sumTwo(x int) int {
return x + 2
}
Pipe2(fp.Filter(isPositive), fp.Map(sumTwo))([]int{1, 2, 3, -1})
// => []int{3, 4, 5}
Curry
将多参数函数转换为单参数函数链。
变体: Curry2
到 Curry16
表示要柯里化的参数数量。
curryedSum := Curry2(func(a int, b int) int { return a + b })
curryedSum(1)(2)
结构体
Option
表示可选值的封装,可用于可能返回或不返回有意义值的函数返回类型。
Option导出: Some
, None
, IsSome
, IsNone
, Chain
, Exists
, Flatten
, FromError
, FromErrorFn
, FromPredicate
, GetOrElse
, Map
, Match
。
Either
表示可以有两种可能类型的值。通常用Right
表示成功值,Left
表示失败值。
Either导出: Left
, Right
, IsLeft
, IsRight
, Exists
, Flatten
, FromError
, FromErrorFn
, FromOption
, FromPredicate
, GetOrElse
, Map
, MapLeft
, Match
。
更多关于golang函数式编程工具集插件库fp-go的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang函数式编程工具集插件库fp-go的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
fp-go: Golang函数式编程工具集使用指南
fp-go 是一个为Go语言设计的函数式编程工具库,它提供了一系列高阶函数和实用工具,帮助开发者以更函数式的方式编写Go代码。
安装
go get github.com/repeale/fp-go
核心功能
1. 集合操作
fp-go 提供了类似JavaScript中Array.map/filter/reduce的功能:
import (
"github.com/repeale/fp-go"
"fmt"
)
func main() {
numbers := []int{1, 2, 3, 4, 5}
// Map: 对每个元素应用函数
doubled := fp.Map(func(x int) int { return x * 2 })(numbers)
fmt.Println(doubled) // [2 4 6 8 10]
// Filter: 过滤元素
evens := fp.Filter(func(x int) bool { return x%2 == 0 })(numbers)
fmt.Println(evens) // [2 4]
// Reduce: 聚合操作
sum := fp.Reduce(func(acc, x int) int { return acc + x }, 0)(numbers)
fmt.Println(sum) // 15
}
2. 函数组合
fp-go 支持函数组合,可以创建更复杂的函数:
import (
"github.com/repeale/fp-go"
"strings"
)
func main() {
toUpper := func(s string) string { return strings.ToUpper(s) }
addExclamation := func(s string) string { return s + "!" }
// 组合函数
shout := fp.Compose(addExclamation, toUpper)
result := shout("hello")
fmt.Println(result) // "HELLO!"
}
3. 柯里化(Currying)
fp-go 支持柯里化,可以将多参数函数转换为一系列单参数函数:
import "github.com/repeale/fp-go"
func main() {
add := func(a, b int) int { return a + b }
// 柯里化
curriedAdd := fp.Curry2(add)
addFive := curriedAdd(5)
result := addFive(3)
fmt.Println(result) // 8
}
4. 实用工具函数
fp-go 提供了一些实用工具函数:
import (
"github.com/repeale/fp-go"
"fmt"
)
func main() {
// 恒等函数
id := fp.Identity(42)
fmt.Println(id) // 42
// 常量函数
alwaysFive := fp.Const(5)
fmt.Println(alwaysFive()) // 5
// 管道操作
result := fp.Pipe(
10,
func(x int) int { return x * 2 },
func(x int) int { return x + 3 },
)
fmt.Println(result) // 23
}
实际应用示例
数据处理管道
import (
"github.com/repeale/fp-go"
"fmt"
"strings"
)
func main() {
data := []string{"apple", "banana", "cherry", "date"}
process := fp.Pipe(
fp.Map(strings.ToUpper),
fp.Filter(func(s string) bool { return len(s) > 5 }),
fp.Map(func(s string) string { return "FRUIT: " + s }),
)
result := process(data)
fmt.Println(result) // [FRUIT: BANANA FRUIT: CHERRY]
}
异步操作组合
import (
"github.com/repeale/fp-go"
"context"
"fmt"
"time"
)
func fetchUser(id int) func() string {
return func() string {
time.Sleep(100 * time.Millisecond)
return fmt.Sprintf("User-%d", id)
}
}
func fetchProfile(user string) func() string {
return func() string {
time.Sleep(100 * time.Millisecond)
return fmt.Sprintf("Profile of %s", user)
}
}
func main() {
// 组合异步操作
getUserProfile := fp.Compose(
fetchProfile,
fetchUser,
)
profile := getUserProfile(1)()
fmt.Println(profile) // "Profile of User-1"
}
注意事项
- fp-go 的函数式风格与Go语言的惯用风格有所不同,使用时需权衡可读性
- 由于Go缺乏泛型(在1.18之前),fp-go 的类型安全性有限
- 性能方面,函数式操作可能比直接循环稍慢
fp-go 为Go开发者提供了函数式编程的便利,但建议根据项目需求适度使用,避免过度抽象影响代码可读性。