Documentation
¶
Overview ¶
Package stream 提供基于 Go 1.27 泛型方法的 Java Stream 风格流式处理库。
流(Stream)不是数据结构,而是从数据源(slice、channel、迭代器、生成器等) 到结果之间的惰性管道:中间操作仅追加管道阶段不触发遍历,终止操作触发一次 单遍求值并返回新容器或聚合值。典型用法:
stream.Of(1, 2, 3).Filter(func(v int) bool { return v > 1 }).Map(strconv.Itoa).ToSlice()
详细设计(架构、错误模型、API 详案)见项目 spec/spec.md。
Example (ErrorAsValue) ¶
错误即值:FromFunc 源失败时部分结果保留,Err() 查询首错。
package main
import (
"fmt"
"github.com/JayceChant/go-stream"
)
func main() {
n := 0
s := stream.FromFunc(func() (int, bool, error) {
n++
if n >= 4 {
return 0, false, fmt.Errorf("第 %d 次读取失败", n)
}
return n, true, nil
})
got := s.ToSlice()
fmt.Println(got)
fmt.Println(s.Err())
}
Output: [1 2 3] 第 4 次读取失败
Example (FromMap) ¶
map 源:FromMap 产出 KV 键值对。
package main
import (
"fmt"
"github.com/JayceChant/go-stream"
)
func main() {
m := map[string]int{"one": 1, "two": 2}
total := 0
stream.FromMap(m).ForEach(func(kv stream.KV[string, int]) {
total += kv.Value
})
fmt.Println(total)
}
Output: 3
Example (InfiniteWithLimit) ¶
无限流 + 短路:Generate 搭配 Limit。
package main
import (
"fmt"
"github.com/JayceChant/go-stream"
)
func main() {
i := 0
got := stream.Generate(func() int { i++; return i * i }).
Limit(5).
ToSlice()
fmt.Println(got)
}
Output: [1 4 9 16 25]
Example (MapTypeChange) ¶
类型迁移:Map 把 int 流变为 string 流(编译期静态类型检查)。
package main
import (
"fmt"
"strconv"
"github.com/JayceChant/go-stream"
"github.com/JayceChant/go-stream/collector"
)
func main() {
got := stream.Of(1, 2, 3).
Map(strconv.Itoa).
Collect(collector.Joining(func(s string) string { return s }, "-"))
fmt.Println(got)
}
Output: 1-2-3
Example (Numeric) ¶
数值聚合:包级 Sum/Avg(方法无法追加 Number 约束)。
package main
import (
"fmt"
"github.com/JayceChant/go-stream"
)
func main() {
fmt.Println(stream.Sum(stream.Range(1, 101)))
fmt.Println(stream.Avg(stream.Range(1, 4)))
}
Output: 5050 2
Example (SortedDistinctPage) ¶
排序去重分页组合。
package main
import (
"fmt"
"github.com/JayceChant/go-stream"
)
func main() {
got := stream.Of(5, 3, 1, 3, 5, 2, 1).
Sorted(func(a, b int) int { return a - b }).
DistinctBy(func(n int) int { return n }).
Skip(1).
Limit(3).
ToSlice()
fmt.Println(got)
}
Output: [2 3 5]
Example (Zip) ¶
双流拉链:Zip 取短。
package main
import (
"fmt"
"github.com/JayceChant/go-stream"
)
func main() {
got := stream.Of("a", "b", "c").
Zip(stream.Range(1, 100), func(s string, i int) string {
return fmt.Sprintf("%s%d", s, i)
}).
ToSlice()
fmt.Println(got)
}
Output: [a1 b2 c3]
Index ¶
- func Avg[N Number](s *Stream[N]) N
- func Cache[T any](s *Stream[T]) func() *Stream[T]
- func Contains[T comparable](s *Stream[T], target T) bool
- func Max[T cmp.Ordered](s *Stream[T]) (T, bool)
- func Min[T cmp.Ordered](s *Stream[T]) (T, bool)
- func Sum[N Number](s *Stream[N]) N
- func Summing[N Number]() collector.Collector[N, *N, N]
- type Characteristics
- type Float
- type Integer
- type KV
- type Number
- type Sink
- type Splitterator
- type Stream
- func Chunk[T any](s *Stream[T], n int) *Stream[[]T]
- func Concat[T any](a, b *Stream[T]) *Stream[T]
- func Distinct[T comparable](s *Stream[T]) *Stream[T]
- func Empty[T any]() *Stream[T]
- func Enumerate[T any](s *Stream[T]) *Stream[KV[int, T]]
- func FromChannel[T any](ch <-chan T) *Stream[T]
- func FromFunc[T any](next func() (T, bool, error)) *Stream[T]
- func FromMap[K comparable, V any](m map[K]V) *Stream[KV[K, V]]
- func FromSeq[T any](seq iter.Seq[T]) *Stream[T]
- func FromSlice[T any](s []T) *Stream[T]
- func Generate[T any](f func() T) *Stream[T]
- func Iterate[T any](seed T, next func(T) T) *Stream[T]
- func Of[T any](xs ...T) *Stream[T]
- func Range[I Integer](start, stop I) *Stream[I]
- func Sorted[T cmp.Ordered](s *Stream[T]) *Stream[T]
- func (s *Stream[T]) AllMatch(p func(T) bool) bool
- func (s *Stream[T]) AnyMatch(p func(T) bool) bool
- func (s *Stream[T]) Close() error
- func (s *Stream[T]) Collect[A, R any](c collector.Collector[T, A, R]) R
- func (s *Stream[T]) Count() int64
- func (s *Stream[T]) DistinctBy[K comparable](key func(T) K) *Stream[T]
- func (s *Stream[T]) DropWhile(p func(T) bool) *Stream[T]
- func (s *Stream[T]) Err() error
- func (s *Stream[T]) Filter(p func(T) bool) *Stream[T]
- func (s *Stream[T]) FilterErr(p func(T) (bool, error)) *Stream[T]
- func (s *Stream[T]) FindAny(p func(T) bool) (T, bool)
- func (s *Stream[T]) First() (T, bool)
- func (s *Stream[T]) FlatMap[U any](f func(T) []U) *Stream[U]
- func (s *Stream[T]) FlatMapErr[U any](f func(T) ([]U, error)) *Stream[U]
- func (s *Stream[T]) FlatMapSeq[U any](f func(T) iter.Seq[U]) *Stream[U]
- func (s *Stream[T]) ForEach(f func(T))
- func (s *Stream[T]) ForEachUntil(f func(T) bool)
- func (s *Stream[T]) Limit(n int64) *Stream[T]
- func (s *Stream[T]) Map[U any](f func(T) U) *Stream[U]
- func (s *Stream[T]) MapErr[U any](f func(T) (U, error)) *Stream[U]
- func (s *Stream[T]) Max(cmp func(a, b T) int) (T, bool)
- func (s *Stream[T]) Min(cmp func(a, b T) int) (T, bool)
- func (s *Stream[T]) NoneMatch(p func(T) bool) bool
- func (s *Stream[T]) OnClose(f func() error) *Stream[T]
- func (s *Stream[T]) Parallel(n int) *Stream[T]
- func (s *Stream[T]) Peek(f func(T)) *Stream[T]
- func (s *Stream[T]) PeekErr(f func(T) error) *Stream[T]
- func (s *Stream[T]) Reduce(identity T, op func(T, T) T) T
- func (s *Stream[T]) ReduceOpt(op func(T, T) T) (T, bool)
- func (s *Stream[T]) Reverse() *Stream[T]
- func (s *Stream[T]) Scan[U any](seed U, f func(U, T) U) *Stream[U]
- func (s *Stream[T]) Sequential() *Stream[T]
- func (s *Stream[T]) Skip(n int64) *Stream[T]
- func (s *Stream[T]) Sorted(cmp func(a, b T) int) *Stream[T]
- func (s *Stream[T]) TakeWhile(p func(T) bool) *Stream[T]
- func (s *Stream[T]) ToSlice() []T
- func (s *Stream[T]) Unordered() *Stream[T]
- func (s *Stream[T]) Zip[U, R any](other *Stream[U], f func(T, U) R) *Stream[R]
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Characteristics ¶
type Characteristics uint16
Characteristics 是数据源结构特征的位标志。
求值器可依据特征位省略不必要的工作(如源已 Sorted 则跳过排序); 后续并行实现(见 spec 后续 TODO)将依赖 Sized/SubSized 做均衡拆分。
const ( // SpSized 表示源可精确报告元素数量(EstimateSize 返回精确值)。 SpSized Characteristics = 1 << iota // SpOrdered 表示源具有确定的相遇顺序,遍历与拆分必须保持该顺序。 SpOrdered // SpSubSized 表示 TrySplit 产生的子源同样可精确报告大小(仅在 SpSized 时有意义)。 SpSubSized // SpSorted 表示源元素按某比较器有序。 SpSorted // SpDistinct 表示源元素两两不重复。 SpDistinct )
type Integer ¶
type Integer interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 |
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
}
Integer 约束全部有符号与无符号整数类型,供 Range 等构造使用。
type KV ¶
type KV[K comparable, V any] struct { Key K Value V }
KV 是键值对元素,供 FromMap(map 源)、Enumerate(索引配对)等场景使用。
type Sink ¶
type Sink[T any] interface { // Begin 在元素推送开始前调用一次,size 为源的估计元素数(未知为 -1), // 便于实现预分配容量等优化。 Begin(size int64) // Accept 接收一个元素;返回 false 表示请求取消(短路), // 引擎将立即停止推动源并调用 End。 Accept(t T) bool // End 在元素推送结束后调用一次(无论正常耗尽还是短路取消)。 // 实现应在此完成收尾(如排序后统一输出)。 End() }
Sink 是推送式消费者接口,是求值期间元素流动的通道。
求值引擎从终止操作出发,将各级中间操作的 Sink 逐级反向包装成一条链, 再由数据源单遍推动元素流过整条链(单遍融合)。
注意:接口方法不得声明自身类型参数(Go 1.27 语言限制),因此本接口 只使用 Stream 的元素类型 T。
type Splitterator ¶
type Splitterator[T any] interface { // TryAdvance 尝试推进到下一个元素:存在则以该元素调用 f 一次并返回 true; // f 返回 false 表示消费方请求短路(实现不得再调用 f);元素耗尽返回 false。 TryAdvance(f func(T) bool) bool // ForEachRemaining 遍历剩余全部元素并逐个调用 f;f 返回 false 时提前结束。 // 默认可基于 TryAdvance 实现,高效源应自行提供。 ForEachRemaining(f func(T) bool) // TrySplit 尝试把剩余元素分裂出一个新的 Splitterator 供并行处理; // 不可分裂(或分裂无益)时返回 nil。串行实现恒为 nil。 TrySplit() Splitterator[T] // EstimateSize 返回剩余元素估计数;未知返回 -1。Sized 特征下为精确值。 EstimateSize() int64 // Characteristics 返回本源的特征位集合。 Characteristics() Characteristics }
Splitterator 是流的数据源抽象:可逐个推进、可整体遍历、可分裂(为并行预留)。
概念对应 Java 的 Spliterator(Go 侧按拼写惯例写作 Splitterator)。 一个 Splitterator 只服务于一次求值:遍历与分裂都会消耗其元素。
type Stream ¶
type Stream[T any] struct { // contains filtered or unexported fields }
Stream 是对外公开的流类型:一条惰性管道的句柄。
通过包级构造函数(Of/FromSlice/FromSeq/Range 等)创建;中间操作以泛型方法 追加阶段并返回新的 *Stream(如 Map[U]);终止操作触发一次求值并消费本流。 同一实例仅可被链接或消费一次,重复使用将 panic(编程错误,不可恢复)。
func Chunk ¶
Chunk 把连续元素切分为定长分组(尾组可能不足 n)。n <= 0 panic。
包级函数形态:Go 1.27 泛型方法返回 Stream[[]T](T 的派生类型)会触发 实例化循环(T → []T → [][]T → ...),只能以包级函数提供。 有状态单遍(跨元素缓冲)→ 并行降级(splitN=nil)。
func Concat ¶
Concat 串联两条流:先耗尽 a 再消费 b(a、b 均被标记消费)。 两段推入同一下游 sink,共用一次 Begin/End(经 suppressEnd 吞掉 a 段 下传的 End,由 b 段统一收尾;b 段自带的 Begin 被 skipBegin 吞掉)。
func Distinct ¶
func Distinct[T comparable](s *Stream[T]) *Stream[T]
Distinct 依据元素自身可比较性去重(保留首见,保持遇序)。 包级函数形态:Go 方法无法对 T 追加 comparable 约束。
func Enumerate ¶
Enumerate 为元素附加从 0 开始的索引,产出 KV[int, T] (对应 Go for i, v := range 习惯)。
包级函数形态:同 Chunk,泛型方法返回 Stream[KV[int, T]] 触发实例化循环。 有状态单遍(递增索引)→ 并行降级(splitN=nil)。
func FromChannel ¶
FromChannel 基于 channel 构建流(阻塞拉取直到通道关闭)。
func FromFunc ¶
FromFunc 基于拉式函数构建流:next 返回 (元素, 是否还有, 错误)。 适配 IO/解析等可失败源;首错经 Err() 查询,出错时保留已产出的部分结果。
func FromMap ¶
func FromMap[K comparable, V any](m map[K]V) *Stream[KV[K, V]]
FromMap 基于 map 构建流,产出 KV 键值对元素。 map 遍历顺序不确定,故本源为 Unordered(不声明 SpOrdered—— Task 10 修正:此前经 newSeqSp 误置 SpOrdered,与本源语义矛盾)。
func Of ¶
Of 以可变参数构建流。
Example ¶
基础链式:构造 → 中间操作 → 终止操作。
package main
import (
"fmt"
"github.com/JayceChant/go-stream"
)
func main() {
got := stream.Of(1, 2, 3, 4, 5).
Filter(func(n int) bool { return n%2 == 1 }).
Map(func(n int) int { return n * n }).
ToSlice()
fmt.Println(got)
}
Output: [1 9 25]
func (*Stream[T]) Close ¶
Close 显式关闭本流:立即触发回调链(幂等——重复调用、求值后再 Close 均不重复执行;未求值的流也可关闭)。返回回调链首错,并记入错误槽 (Err() 可查询)。
func (*Stream[T]) Collect ¶
Collect 以自定义收集器汇聚元素(泛型方法,支持 A→R 类型迁移)。 并行流:片级独立累积,按分片序以 Combiner 合并,Finisher 收尾。 收集器族见子包 collector(stream/collector)。
func (*Stream[T]) DistinctBy ¶
func (s *Stream[T]) DistinctBy[K comparable](key func(T) K) *Stream[T]
DistinctBy 依据 key 函数去重:每组同 key 仅保留首个遇到的元素(保遇序)。 K 须满足 comparable:键为具体不可比较类型(slice/map/func 等)时编译期即报错。 逃生口:K 显式取 any(接口满足 comparable)仍可编译,动态类型不可比较时 在求值时 panic(用户契约,同 map 键语义)。
func (*Stream[T]) FlatMapErr ¶
FlatMapErr 带错误返回的 FlatMap。
func (*Stream[T]) FlatMapSeq ¶
FlatMapSeq 与 FlatMap 相同,但展开函数返回 iter.Seq(支持惰性子序列)。
func (*Stream[T]) ForEach ¶
func (s *Stream[T]) ForEach(f func(T))
ForEach 对每个元素执行 f(并行流下按相遇序合并、f 在发起 goroutine 串行调用;Unordered 流例外:按分片完成序推入,顺序不保证)。
func (*Stream[T]) ForEachUntil ¶
ForEachUntil 对每个元素执行 f;f 返回 false 时提前终止。
func (*Stream[T]) Map ¶
Map 将每个元素经 f 变换为新类型 U(泛型方法,元素类型迁移)。 1:1 变换:保留 SpSized(下游可按 size 预分配),仅清 SpSorted/SpDistinct。
func (*Stream[T]) MapErr ¶
MapErr 带错误返回的 Map:f 出错时记录首错并终止求值。 1:1 变换:保留 SpSized,仅清 SpSorted/SpDistinct。
func (*Stream[T]) OnClose ¶
OnClose 注册资源清理回调 f:返回携带回调链的新流(中间操作语义: 消费本流,已注册的回调链一并继承)。f 为 nil 时 panic(编程错误)。
触发时机:新流(或其任一下游)的终止求值结束时自动触发一次—— 正常耗尽、短路与错误值路径均触发,用户回调 panic 的展开路径亦触发; 求值前显式调用过 Close 则以显式关闭为准。多个回调按注册顺序执行; 任一出错记录首错(不 panic,可经 Err() 查询)。
幂等保证:每个物理回调以 sync.Once 包装——无论经由求值自动触发、 任一 stage 实例的显式 Close、还是组合流(Concat/Zip 继承合并后的 回调链)触发,均恰好执行一次。
func (*Stream[T]) Parallel ¶
Parallel 声明后续求值以最多 n 个分片并行(中间操作语义:消费上游, 返回携带并行标志的新流)。n <= 1 或不可分源/含降级算子的管道自动串行。
func (*Stream[T]) Peek ¶
Peek 对每个元素施加副作用 f(不改变元素,常用于调试观察)。 并行流下 f 在分片 goroutine 内执行,观察顺序不保证(需保序请用 ForEach)。
func (*Stream[T]) Reduce ¶
func (s *Stream[T]) Reduce(identity T, op func(T, T) T) T
Reduce 以 identity 为初值折叠全部元素(并行流片内折叠、片序合并)。
func (*Stream[T]) Scan ¶
Scan 滚动累积(前缀和式):输出 seed, f(seed,x1), f(f(seed,x1),x2), ... 输出个数与输入相同(含初值,比 Java 无对应物的常见 Go 实现多一项)。 有状态单遍(滚动 acc)→ 并行降级(splitN=nil)。
func (*Stream[T]) Sequential ¶
Sequential 还原串行求值(抵消上游 Parallel 声明)。
func (*Stream[T]) Skip ¶
Skip 跳过前 n 个元素,输出其余(n == 0 恒等返回原流,不物化、特征位透传; n < 0 panic)。恒等返回时不标记上游 consumed,原流仍可继续链接。