golang lodash风格的高效工具库插件gofp的使用
golang lodash风格的高效工具库插件gofp的使用
一个简单的Go工具库
Go语言在数据结构如slice和map方面没有提供许多基本的内置函数。这个库提供了最常用的工具函数,灵感来自lodash(一个Javascript工具库)。
gofp的主要特性
- 使用
Pipe()
,Compose()
,Reduce()
,Map()
,Filter()
,Extend()
,Find()
等函数更容易实现函数式编程 - 该库提供了许多处理集合或切片相关操作的实用函数
- 通过
Get
函数可以轻松访问map、slice甚至结构体中的任何属性 - 工具函数基于
interface{}
实现,主要目标是尽可能不使用reflect
包
安装
在终端运行以下命令安装:
go get github.com/rbrahul/gofp
如何使用?
以下示例展示了如何使用gofp
实现pipe
操作:
package main
import (
"fmt"
"strings"
"github.com/rbrahul/gofp"
)
func main() {
user := map[string]interface{}{
"name": "John Doe",
"age": 30,
"contacts": map[string]interface{}{
"email": "johndoe@gmail.com",
"office": "Google Inc.",
"fax": map[string]interface{}{
"uk": "+44-208-1234567",
},
},
}
getContacts := func(data interface{}) interface{} {
return data.(map[string]interface{})["contacts"]
}
getEmail := func(data interface{}) interface{} {
return data.(map[string]interface{})["email"]
}
getUpperCaseEmail := func(data interface{}) interface{} {
return strings.ToUpper(data.(string))
}
email := gofp.Pipe(
getContacts,
getEmail,
getUpperCaseEmail,
)(user)
fmt.Println("Email is: ", email) // Output: Email is: JOHNDOE@GMAIL.COM
}
文档
集合或切片最常用的工具函数
Map()
返回一个新的切片,对每个元素执行迭代器函数。Map有2个参数,第1个是切片,第2个是迭代器函数。迭代器函数必须有2个参数,索引和当前迭代值。
...
mappedItems := Map([]interface{}{1, 2, 3, 4, 5},
func(i int, item interface{}) interface{} {
return item.(int) * item.(int)
})
fmt.Println(mappedItems) //Output: 1, 4, 9, 16, 25
...
Filter()
返回一个包含过滤元素的新切片。新切片包含满足迭代器函数条件的元素。
...
filteredItems := Filter([]interface{}{12, 16, 18, 20, 23, 40, 25},
func(i int, age interface{}) bool {
return age.(int) >= 20
})
fmt.Println(filteredItems) //Output: 20, 23, 40, 25
...
Find()
返回切片中第一个满足迭代器函数条件的元素。如果没有满足条件的元素则返回nil。
...
user := Find([]interface{}{
map[string]interface{}{"name": "Ron", "sex": "male", "age": 17},
map[string]interface{}{"name": "Raymond", "sex": "male", "age": 20},
map[string]interface{}{"name": "Sofia", "sex": "female", "age": 20},
map[string]interface{}{"name": "Roni", "sex": "male", "age": 30},
}, func(i int, person interface{}) bool {
return person.(map[string]interface{})["age"].(int) >= 18
})
fmt.Println(user) //Output: {"name": "Raymond", "sex": "male", "age": 20}
...
Reduce()
对切片中的每个元素执行迭代器函数,最终得到一个累积值。
...
reducedItems := Reduce([]interface{}{10, 20, 30, 40},
func(index int, current interface{}, accumulator interface{}, source []interface{}) interface{} {
return accumulator.(int) + current.(int)
}, 0)
fmt.Println(reducedItems) //Output: 100
...
Every()
如果每个元素都匹配给定迭代器函数的条件则返回true
。
...
isEveryOneIsAdult := Every([]interface{}{18, 20, 23, 40, 25},
func(i int, age interface{}) bool {
return age.(int) >= 18
})
fmt.Println(isEveryOneIsAdult) //Output: true
...
Any()
如果有任何元素匹配给定迭代器函数的条件则返回true
。
...
hasAnyAdult := Any([]interface{}{18, 20, 23, 40, 25},
func(i int, age interface{}) bool {
return age.(int) >= 18
})
fmt.Println(hasAnyAdult) //Output: true
...
GroupBy()
返回一个新的map,键是迭代器函数的运行结果。
...
groupedData := GroupBy([]interface{}{
map[string]interface{}{"name": "Ron", "sex": "male", "age": 17},
map[string]interface{}{"name": "Raymond", "sex": "male", "age": 20},
map[string]interface{}{"name": "Sofia", "sex": "female", "age": 20},
map[string]interface{}{"name": "Roni", "sex": "male", "age": 30},
}, func(person interface{}) string {
return strconv.Itoa(person.(map[string]interface{})["age"].(int))
})
fmt.Println(groupedData)
/*
Output:
{
"17": [{"name": "Ron", "sex": "male", "age": 17}],
"20": [
{"name": "Raymond", "sex": "male", "age": 20},
{"name": "Sofia", "sex": "female", "age": 20}
],
"30": [{"name": "Roni", "sex": "male", "age": 30}]
}
*/
...
Chunk()
返回一个新的切片切片,每个子切片有固定数量的元素。
...
chunkedItems := Chunk([]interface{}{1, 2, 3, 4, 5}, 2)
fmt.Println(chunkedItems) //Output: {{1,2},{3,4},{5}}
...
Reverse()
返回一个元素顺序反转的新切片。
...
reveresed := Reverse([]interface{}{10, 20, 30, 40, 50})
fmt.Println(reveresed) //Output: {50,40,30,20,10}
...
Range()
返回一个从第1个参数到第2个参数的范围切片。
...
rangeItems := Range(5, 10)
fmt.Println(rangeItems) //Output: {5,6,7,8,9,10}
...
Uniq()
返回一个去重后的新切片。
...
uniqueItems := Uniq([]interface{}{1, 2, 2, 3, 10, 4, 5, 10, 100})
fmt.Println(uniqueItems) //Output: {1,2,3,10,4,5,100}
...
Head()
返回切片的第一个元素。
...
firstItem := Head([]interface{}{
map[string]interface{}{"name": "Ron", "sex": "male", "age": 17},
map[string]interface{}{"name": "Raymond", "sex": "male", "age": 20},
map[string]interface{}{"name": "Sofia", "sex": "female", "age": 20},
map[string]interface{}{"name": "Roni", "sex": "male", "age": 30},
})
fmt.Println(firstItem) //Output: {"name": "Ron", "sex": "male", "age": 17}
...
Tail()
返回切片的最后一个元素。
...
lastItem := Tail([]interface{}{
map[string]interface{}{"name": "Ron", "sex": "male", "age": 17},
map[string]interface{}{"name": "Raymond", "sex": "male", "age": 20},
map[string]interface{}{"name": "Sofia", "sex": "female", "age": 20},
map[string]interface{}{"name": "Roni", "sex": "male", "age": 30},
})
fmt.Println(lastItem) //Output: {"name": "Roni", "sex": "male", "age": 30}
...
Fill()
返回一个新切片,从开始到结束索引用给定字符串替换所有元素。
...
filledItems := Fill([]interface{}{1, 2, 3, 4, 5, 6, 7}, "*", 1, 5)
fmt.Println(filledItems) //Output: {1, *, *, *, *, 6, 7}
...
IndexOf()
返回切片中第一次出现给定元素的索引。
...
index := IndexOf([]interface{}{1, 2, 2, 3, 10, 4, 5, 10, 100}, 10)
fmt.Println(index) //Output: 4
...
Contains()
如果给定元素存在于切片中则返回true
。
...
exists := Contains([]interface{}{1, 2, 2, 3, 10, 4, 5, 10, 100}, 10)
fmt.Println(exists) //Output: true
...
ChooseRandom()
随机返回切片中的一个元素。
...
randomElement := ChooseRandom([]interface{}{1, 2, 3, 4, 5, 10, 100})
fmt.Println("Could be any:",randomElement) //Output Could be any: 4
...
Shuffle()
返回一个元素随机排序的新切片。
...
shuffledItems := ChooseRandom([]interface{}{1, 2, 3, 4, 5, 10, 100})
fmt.Println(shuffledItems) //Output: {100, 2, 1, 4, 5, 3, 10}
...
Map相关的工具函数
Keys()
返回map的键切片。
...
keys := Keys(map[string]interface{}{
"firstName": "John",
"lastName": "Doe",
"age": 32
})
fmt.Println(keys) //Output: {firstName, lastName, age}
...
Values()
返回map的值切片。
...
values := Values(map[string]interface{}{
"firstName": "John",
"lastName": "Doe",
"age": 32
})
fmt.Println(values) //Output: {John, Doe, 32}
...
Has()
如果键存在于map中则返回true
。
...
exists := Has(map[string]interface{}{
"firstName": "John",
"lastName": "Doe",
"age": 32
}, "age")
fmt.Println(exists) //Output: true
...
Pick()
返回一个新map,只包含指定的属性。
...
pickedData := Pick(map[string]interface{}{
"firstName": "John",
"lastName": "Doe",
"age": 32
}, []string{"lastName"})
fmt.Println(pickedData) //Output: {"lastName": "Doe"}
...
Omit()
返回一个新map,省略给定的键。
...
omittedData := Omit(map[string]interface{}{
"firstName": "John",
"lastName": "Doe",
"age": 32
}, []string{"lastName"})
fmt.Println(omittedData) //Output: {"firstName": "John", "age": 32}
...
MapValues()
返回一个新map,对每个值应用迭代器函数。
...
mappedValues := MapValues(map[string]interface{}{
"firstName": "john",
"lastName": "doe",
"gender": "unknown"}, func(value interface{}) interface{} {
return strings.Title(value.(string))
})
fmt.Println(mappedValues) //Output: {"firstName": "JOHN", "lastName":"DOE": 32, "gender":"UNKNOWN"}
...
MapKeys()
返回一个新map,对每个键应用迭代器函数。
...
mappedKeys := MapKeys(map[string]interface{}{
"firstName": "john",
"lastName": "doe",
"gender": "unknown"}, func(value interface{}) interface{} {
return strings.Title(value.(string))
})
fmt.Println(mappedKeys) //Output: {"FIRSTNAME": "john","LASTNAME": "doe","GENDER": "unknown"}
...
Get()
返回给定路径的值。如果没有数据则返回nil
。
...
data := map[string]interface{}{
"age": 30,
"male": true,
"contacts": map[string]interface{}{
"office": 12345,
"fax": map[string]interface{}{
"uk": "+44-208-1234567",
},
"address": map[string]interface{}{
"post_code": "SW3",
"street": "10 Downing Street",
"geo_location": []string{"51.529011463529636", "-0.1098365614770662"},
},
},
}
geoLocationFromGet := Get(data, "contacts.address.geo_location.0")
fmt.Println(geoLocationFromGet) //Output: 51.529011463529636
...
Extend()
返回一个新map,用给定map扩展值。
...
extendedMap := Extends(
map[string]interface{}{
"firstName": "john",
"lastName": "doe",
"gender": "unknown"
},
map[string]interface{}{
"gender": "male"
})
fmt.Println(extendedMap) //Output: {"firstName": "john","lastName": "doe","gender": "male"}
...
更多关于golang lodash风格的高效工具库插件gofp的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang lodash风格的高效工具库插件gofp的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
gofp - Golang 的 Lodash 风格工具库
gofp 是一个受 JavaScript 的 Lodash 库启发的 Golang 实用工具库,提供了许多函数式编程风格的实用函数,可以大大简化日常开发中的集合操作、数据处理等任务。
安装
go get github.com/rbrahul/gofp
主要功能与示例
1. 集合操作
package main
import (
"fmt"
"github.com/rbrahul/gofp"
)
func main() {
// 过滤
numbers := []int{1, 2, 3, 4, 5, 6}
even := gofp.Filter(numbers, func(n int) bool {
return n%2 == 0
})
fmt.Println(even) // [2 4 6]
// 映射
doubled := gofp.Map(numbers, func(n int) int {
return n * 2
})
fmt.Println(doubled) // [2 4 6 8 10 12]
// 归约
sum := gofp.Reduce(numbers, func(acc, curr int) int {
return acc + curr
}, 0)
fmt.Println(sum) // 21
}
2. 查找操作
// 查找第一个匹配项
found := gofp.Find(numbers, func(n int) bool {
return n > 3
})
fmt.Println(found) // 4
// 检查是否存在匹配项
exists := gofp.Contains(numbers, 5)
fmt.Println(exists) // true
// 查找索引
index := gofp.FindIndex(numbers, func(n int) bool {
return n == 3
})
fmt.Println(index) // 2
3. 切片操作
// 分块
chunks := gofp.Chunk(numbers, 2)
fmt.Println(chunks) // [[1 2] [3 4] [5 6]]
// 去重
duplicates := []int{1, 2, 2, 3, 4, 4, 5}
unique := gofp.Uniq(duplicates)
fmt.Println(unique) // [1 2 3 4 5]
// 差集
a := []int{1, 2, 3, 4}
b := []int{2, 4, 5}
diff := gofp.Difference(a, b)
fmt.Println(diff) // [1 3]
4. 实用函数
// 随机打乱
shuffled := gofp.Shuffle(numbers)
fmt.Println(shuffled) // 随机顺序
// 分组
type Person struct {
Name string
Age int
}
people := []Person{
{"Alice", 25},
{"Bob", 30},
{"Charlie", 25},
}
grouped := gofp.GroupBy(people, func(p Person) int {
return p.Age
})
fmt.Println(grouped) // map[25:[{Alice 25} {Charlie 25}] 30:[{Bob 30}]]
// 键值对转换
keyBy := gofp.KeyBy(people, func(p Person) string {
return p.Name
})
fmt.Println(keyBy) // map[Alice:{Alice 25} Bob:{Bob 30} Charlie:{Charlie 25}]
5. 链式调用
result := gofp.Chain(numbers).
Filter(func(n int) bool { return n > 2 }).
Map(func(n int) int { return n * 3 }).
Value()
fmt.Println(result) // [9 12 15 18]
性能考虑
gofp 在设计时考虑了性能因素:
- 大多数操作都是 O(n) 时间复杂度
- 避免不必要的内存分配
- 提供直接的函数调用而非复杂的对象模型
与原生 Go 代码对比
虽然 Go 的标准库已经提供了一些基础功能,但 gofp 提供了更简洁的 API:
// 原生 Go 过滤
var filtered []int
for _, n := range numbers {
if n%2 == 0 {
filtered = append(filtered, n)
}
}
// gofp 方式
filtered := gofp.Filter(numbers, func(n int) bool { return n%2 == 0 })
适用场景
- 数据处理和转换
- API 响应处理
- 集合操作密集的业务逻辑
- 需要函数式编程风格的代码
注意事项
- 对于极高性能敏感的场景,直接循环可能更高效
- 某些复杂操作可能不如专门优化的代码高效
- 类型安全需要开发者自己保证
gofp 为 Golang 开发者提供了一种更简洁、更声明式的编程方式,特别适合那些熟悉 Lodash 风格 API 的开发者。