golang实现惰性求值与函数式数组操作的插件库koazee的使用
Golang实现惰性求值与函数式数组操作的插件库Koazee的使用
Koazee是一个StreamLike、不可变、惰性加载且智能的Golang库,用于处理切片(slices)。它提供了类似函数式编程的操作方式,同时保持高性能。
Koazee特点
- 不可变(Immutable): Koazee不会修改输入数据
- 流式操作(StreamLike): 可以方便地组合多个操作
- 惰性加载(Lazy loading): 操作在真正需要时才会执行
- 通用(Generic): 可以处理任何类型的切片,无需创建自定义函数
- 高性能(Focusing on performance): 实现新操作时的首要考虑是提供最佳性能
安装
使用Go modules安装:
module github.com/me/project
require (
github.com/wesovilabs/koazee vX.Y.Z
)
或者使用go get:
go get github.com/wesovilabs/koazee
基本使用示例
创建流
package main
import (
"fmt"
"github.com/wesovilabs/koazee"
)
var numbers = []int{1, 5, 4, 3, 2, 7, 1, 8, 2, 3}
func main() {
fmt.Printf("slice: %v\n", numbers)
stream := koazee.StreamOf(numbers)
fmt.Printf("stream: %v\n", stream.Out().Val())
}
/**
输出:
slice: [1 5 4 3 2 7 1 8 2 3]
stream: [1 5 4 3 2 7 1 8 2 3]
*/
元素访问操作
package main
import (
"fmt"
"github.com/wesovilabs/koazee"
)
var numbers = []int{1, 5, 4, 3, 2, 7, 1, 8, 2, 3}
func main() {
stream := koazee.StreamOf(numbers)
fmt.Printf("stream.At(4): %d\n", stream.At(4).Int())
fmt.Printf("stream.First: %d\n", stream.First().Int())
fmt.Printf("stream.Last: %d\n", stream.Last().Int())
}
/**
输出:
stream.At(4): 2
stream.First: 1
stream.Last: 3
*/
添加/删除元素
package main
import (
"fmt"
"github.com/wesovilabs/koazee"
)
var numbers = []int{1, 5, 4, 3, 2, 7, 1, 8, 2, 3}
func main() {
fmt.Printf("input: %v\n", numbers)
stream := koazee.StreamOf(numbers)
fmt.Print("stream.Add(10): ")
fmt.Println(stream.Add(10).Do().Out().Val())
fmt.Print("stream.Drop(5): ")
fmt.Println(stream.Drop(5).Do().Out().Val())
fmt.Print("stream.DropWhile(val<=5): ")
fmt.Println(stream.DropWhile(func(element int)bool{return element<=5}).Do().Out().Val())
fmt.Print("stream.DeleteAt(4): ")
fmt.Println(stream.DeleteAt(4).Do().Out().Val())
fmt.Print("stream.Set(0,5): ")
fmt.Println(stream.Set(0, 5).Do().Out().Val())
fmt.Print("stream.Pop(): ")
val, newStream := stream.Pop()
fmt.Printf("%d ... ", val.Int())
fmt.Println(newStream.Out().Val())
}
/**
输出:
input: [1 5 4 3 2 7 1 8 2 3]
stream.Add(10): [1 5 4 3 2 7 1 8 2 3 10]
stream.Drop(5): [1 4 3 2 7 1 8 2 3]
stream.DropWhile(val<=5): [7 8]
stream.DeleteAt(4): [1 5 4 3 7 1 8 2 3]
stream.Set(0,5): [5 5 4 3 2 7 1 8 2 3]
stream.Pop(): 1 ... [5 4 3 2 7 1 8 2 3]
*/
元素信息查询
package main
import (
"fmt"
"github.com/wesovilabs/koazee"
)
var numbers = []int{1, 5, 4, 3, 2, 7, 1, 8, 2, 3}
func main() {
fmt.Printf("input: %v\n", numbers)
stream := koazee.StreamOf(numbers)
count, _ := stream.Count()
fmt.Printf("stream.Count(): %d\n", count)
index, _ := stream.IndexOf(2)
fmt.Printf("stream.IndexOf(2): %d\n", index)
indexes, _ := stream.IndexesOf(2)
fmt.Printf("stream.IndexesOf(2): %d\n", indexes)
index, _ = stream.LastIndexOf(2)
fmt.Printf("stream.LastIndexOf(2): %d\n", index)
contains, _ := stream.Contains(7)
fmt.Printf("stream.Contains(7): %v\n", contains)
}
/**
输出:
input: [1 5 4 3 2 7 1 8 2 3]
stream.Count(): 10
stream.IndexOf(2): 4
stream.IndexesOf(2): [4 8]
stream.LastIndexOf(2): 8
stream.Contains(7): true
*/
排序和反转
package main
import (
"fmt"
"github.com/wesovilabs/koazee"
"strings"
)
var animals = []string{"lynx", "dog", "cat", "monkey", "fox", "tiger", "lion"}
func main() {
fmt.Print("input: ")
fmt.Println(animals)
stream := koazee.StreamOf(animals)
fmt.Print("stream.Reverse(): ")
fmt.Println(stream.Reverse().Out().Val())
fmt.Print("stream.Sort(strings.Compare): ")
fmt.Println(stream.Sort(strings.Compare).Out().Val())
}
/**
输出:
input: [lynx dog cat monkey fox tiger lion]
stream.Reverse(): [lion tiger fox monkey cat dog lynx]
stream.Sort(strings.Compare): [cat dog fox lion lynx monkey tiger]
*/
过滤操作
package main
import (
"fmt"
"github.com/wesovilabs/koazee"
)
var animals = []string{"lynx", "dog", "cat", "monkey", "dog", "fox", "tiger", "lion"}
func main() {
fmt.Print("input: ")
fmt.Println(animals)
stream := koazee.StreamOf(animals)
fmt.Print("stream.Take(1,4): ")
fmt.Println(stream.Take(1, 4).Out().Val())
fmt.Print("stream.Filter(len==4): ")
fmt.Println(stream.
Filter(
func(val string) bool {
return len(val) == 4
}).
Out().Val(),
)
fmt.Print("stream.RemoveDuplicates(): ")
fmt.Println(stream.RemoveDuplicates().Out().Val())
}
/**
输出:
input: [lynx dog cat monkey dog fox tiger lion]
stream.Take(1,4): [dog cat monkey dog]
stream.Filter(len==4): [lynx lion]
stream.RemoveDuplicates(): [lynx dog cat monkey fox tiger lion]
*/
分组操作
package main
import (
"fmt"
"github.com/wesovilabs/koazee"
"strings"
)
var animals = []string{"lynx", "dog", "cat", "monkey", "dog", "fox", "tiger", "lion"}
func main() {
fmt.Printf("input: %v\n", animals)
stream := koazee.StreamOf(animals)
fmt.Print("stream.GroupBy(strings.Len): ")
out, _ := stream.GroupBy(func(val string)int{return len(val)})
fmt.Println(out)
}
/**
输出:
input: [lynx dog cat monkey dog fox tiger lion]
stream.GroupBy(strings.Len): map[5:[tiger] 4:[lynx lion] 3:[dog cat dog fox] 6:[monkey]]
*/
映射操作
package main
import (
"fmt"
"github.com/wesovilabs/koazee"
"strings"
)
var animals = []string{"lynx", "dog", "cat", "monkey", "dog", "fox", "tiger", "lion"}
func main() {
fmt.Printf("input: %v\n", animals)
stream := koazee.StreamOf(animals)
fmt.Print("stream.Map(strings.Title): ")
fmt.Println(stream.Map(strings.Title).Do().Out().Val())
}
/**
输出:
input: [lynx dog cat monkey dog fox tiger lion]
stream.Map(strings.Title): [Lynx Dog Cat Monkey Dog Fox Tiger Lion]
*/
归约操作
package main
import (
"fmt"
"github.com/wesovilabs/koazee"
)
var numbers = []int{1, 5, 4, 3, 2, 7, 1, 8, 2, 3}
func main() {
fmt.Printf("input: %v\n", numbers)
stream := koazee.StreamOf(numbers)
fmt.Print("stream.Reduce(sum): ")
fmt.Println(stream.Reduce(func(acc, val int) int {
return acc + val
}).Int())
}
/**
输出:
input: [1 5 4 3 2 7 1 8 2 3]
stream.Reduce(sum): 36
*/
遍历操作
package main
import (
"fmt"
"github.com/wesovilabs/koazee"
)
type message struct {
user string
message string
}
var messages = []*message{
{user: "John", message: "Hello Jane"},
{user: "Jane", message: "Hey John, how are you?"},
{user: "John", message: "I'm fine! and you?"},
{user: "Jane", message: "Me too"},
}
func main() {
stream := koazee.StreamOf(messages)
stream.ForEach(func(m *message) {
fmt.Printf("%s: \"%s\"\n", m.user, m.message)
}).Do()
}
/**
输出:
John: "Hello Jane"
Jane: "Hey John, how are you?"
John: "I'm fine! and you?"
Jane: "Me too"
*/
组合操作与惰性求值
Koazee的主要目标是提供一组可以组合并且惰性求值的操作:
package main
import (
"fmt"
"github.com/wesovilabs/koazee"
"strings"
)
type Person struct {
Name string
Male bool
Age int
}
var people = []*Person{
{"John Smith", true, 32},
{"Peter Pan", true, 17},
{"Jane Doe", false, 20},
{"Anna Wallace", false, 35},
{"Tim O'Brian", true, 13},
{"Celia Hills", false, 15},
}
func main() {
stream := koazee.
StreamOf(people).
Filter(func(person *Person) bool {
return !person.Male
}).
Sort(func(person, otherPerson *Person) int {
return strings.Compare(person.Name, otherPerson.Name)
}).
ForEach(func(person *Person) {
fmt.Printf("%s is %d years old\n", person.Name, person.Age)
})
fmt.Println("Operations are not evaluated until we perform stream.Do()\n")
stream.Do()
}
/**
输出:
Operations are not evaluated until we perform stream.Do()
Anna Wallace is 35 years old
Celia Hills is 15 years old
Jane Doe is 20 years old
*/
可用操作列表
操作 | 描述 | 版本 |
---|---|---|
Add | 在最后位置添加新元素 | v0.0.1 |
At | 返回给定位置的元素 | v0.0.1 |
Contains | 检查流中是否存在给定元素 | v0.0.1 |
Count | 返回流中元素数量 | v0.0.1 |
DeleteAt | 删除给定位置的元素 | v0.0.3 |
Drop | 从流中移除元素 | v0.0.1 |
DropWhile | 移除流中与给定函数匹配的元素 | v0.0.4 |
Filter | 丢弃与提供过滤器不匹配的元素 | v0.0.1 |
First | 返回第一个位置的元素 | v0.0.1 |
ForEach | 对流中所有元素执行操作 | v0.0.1 |
GroupBy | 根据返回的函数值创建分组 | v0.0.4 |
IndexOf | 返回元素在流中的第一个索引 | v0.0.3 |
IndexesOf | 返回元素在流中所有出现的索引 | v0.0.4 |
Last | 返回最后一个位置的元素 | v0.0.1 |
LastIndexOf | 返回元素在流中最后一次出现的索引 | v0.0.3 |
Map | 转换流中的元素 | v0.0.1 |
Pop | 提取流中的第一个元素并返回该元素和新流 | v0.0.3 |
Reduce | 通过为流的每个值执行提供的函数将流减少为单个值 | v0.0.1 |
RemoveDuplicates | 移除重复元素 | v0.0.1 |
Reverse | 反转流中元素的顺序 | v0.0.3 |
Set | 用提供的值替换给定索引处的元素 | v0.0.3 |
Sort | 对流中的元素进行排序 | v0.0.1 |
Take | 返回给定索引之间的元素的流 | v0.0.3 |
Koazee提供了丰富的函数式操作,可以方便地处理切片数据,同时保持惰性求值和不可变性等函数式编程特性。
更多关于golang实现惰性求值与函数式数组操作的插件库koazee的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang实现惰性求值与函数式数组操作的插件库koazee的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang惰性求值与函数式数组操作:koazee库使用指南
什么是koazee
koazee是一个Go语言库,提供了类似Lodash或Underscore的功能,允许开发者以函数式风格处理集合数据。它的特点是支持惰性求值(Lazy Evaluation),这意味着操作不会立即执行,而是在需要结果时才进行计算。
主要特性
- 惰性求值:操作链不会立即执行,直到需要结果时才计算
- 不可变数据:所有操作都返回新的集合,不会修改原数据
- 链式调用:支持流畅的链式API
- 类型安全:编译时类型检查
安装
go get github.com/wesovilabs/koazee
基本使用示例
1. 创建流(Stream)
package main
import (
"fmt"
"github.com/wesovilabs/koazee"
)
func main() {
// 从切片创建流
numbers := []int{1, 2, 3, 4, 5}
stream := koazee.StreamOf(numbers)
// 直接创建流
stream2 := koazee.StreamOf(1, 2, 3, 4, 5)
fmt.Println(stream.Out().Val()) // [1 2 3 4 5]
fmt.Println(stream2.Out().Val()) // [1 2 3 4 5]
}
2. 基本操作
// 过滤
filtered := stream.
Filter(func(num int) bool { return num%2 == 0 }).
Out().Val()
fmt.Println(filtered) // [2 4]
// 映射
mapped := stream.
Map(func(num int) int { return num * 2 }).
Out().Val()
fmt.Println(mapped) // [2 4 6 8 10]
// 归约
sum := stream.
Reduce(func(acc, num int) int { return acc + num }).
Out().Val()
fmt.Println(sum) // 15
3. 惰性求值示例
lazyStream := koazee.StreamOf(1, 2, 3, 4, 5).
Map(func(x int) int {
fmt.Printf("Processing %d\n", x)
return x * 2
}).
Filter(func(x int) bool {
return x > 5
})
// 此时还没有任何输出,因为操作是惰性的
result := lazyStream.Out().Val()
// 输出:
// Processing 1
// Processing 2
// Processing 3
// Processing 4
// Processing 5
fmt.Println(result) // [6 8 10]
4. 更多实用操作
// 去重
unique := koazee.StreamOf(1, 2, 2, 3, 3, 3).
RemoveDuplicates().
Out().Val()
fmt.Println(unique) // [1 2 3]
// 排序
sorted := koazee.StreamOf(3, 1, 4, 2).
Sort(func(a, b int) int {
if a < b {
return -1
} else if a > b {
return 1
}
return 0
}).
Out().Val()
fmt.Println(sorted) // [1 2 3 4]
// 取前N个
firstTwo := koazee.StreamOf(1, 2, 3, 4, 5).
Take(2).
Out().Val()
fmt.Println(firstTwo) // [1 2]
5. 复杂类型操作
type Person struct {
Name string
Age int
}
people := []Person{
{"Alice", 25},
{"Bob", 30},
{"Charlie", 20},
}
// 按年龄过滤
youngPeople := koazee.StreamOf(people).
Filter(func(p Person) bool { return p.Age < 30 }).
Out().Val()
fmt.Println(youngPeople) // [{Alice 25} {Charlie 20}]
// 提取姓名
names := koazee.StreamOf(people).
Map(func(p Person) string { return p.Name }).
Out().Val()
fmt.Println(names) // [Alice Bob Charlie]
性能考虑
虽然koazee提供了方便的API,但需要注意:
- 惰性求值会带来一定的内存开销
- 对于小型数据集,性能差异不明显
- 对于大型数据集或性能敏感场景,建议进行基准测试
与标准库对比
// 标准库实现过滤
var filteredStd []int
for _, num := range numbers {
if num%2 == 0 {
filteredStd = append(filteredStd, num)
}
}
// koazee实现
filteredKoazee := koazee.StreamOf(numbers).
Filter(func(num int) bool { return num%2 == 0 }).
Out().Val()
koazee代码更简洁,但标准库版本通常性能更好。
总结
koazee为Go语言带来了函数式编程风格和惰性求值能力,特别适合:
- 需要处理复杂数据转换的场景
- 希望代码更声明式、更易读的情况
- 不处于极端性能敏感路径的代码
对于简单的操作,标准库可能更合适,但对于复杂的数据处理管道,koazee可以显著提高代码的可读性和可维护性。