[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-92504":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":16,"stars30d":13,"stars90d":16,"forks30d":16,"starsTrendScore":16,"compositeScore":17,"rankGlobal":10,"rankLanguage":10,"license":18,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":21,"hasPages":21,"topics":22,"createdAt":10,"pushedAt":10,"updatedAt":23,"readmeContent":24,"aiSummary":25,"trendingCount":16,"starSnapshotCount":16,"syncStatus":26,"lastSyncTime":27,"discoverSource":28},92504,"seq","smallnest\u002Fseq","smallnest","A generic library in Golang with generic method feature","http:\u002F\u002Fcolobu.com\u002Fseq\u002F",null,"Go",53,1,51,3,0,41,"MIT License",false,"master",true,[],"2026-07-22 04:02:06","# seq\n\n[![Go Reference](https:\u002F\u002Fpkg.go.dev\u002Fbadge\u002Fgithub.com\u002Fsmallnest\u002Fseq.svg)](https:\u002F\u002Fpkg.go.dev\u002Fgithub.com\u002Fsmallnest\u002Fseq)\n[![CI](https:\u002F\u002Fgithub.com\u002Fsmallnest\u002Fseq\u002Factions\u002Fworkflows\u002Fci.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fsmallnest\u002Fseq\u002Factions\u002Fworkflows\u002Fci.yml)\n[![Go Version](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FGo-%3E%3D1.27-blue)](https:\u002F\u002Fgo.dev\u002F)\n[![License](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-MIT-green)](LICENSE)\n\nEnglish | [简体中文](README_CN.md)\n\n**Chainable, lazy collection pipelines for Go, built on `iter.Seq`.**\n\n`seq` is a generic Go library that wraps the standard library's lazy iterators `iter.Seq` \u002F `iter.Seq2` (Go 1.23+) and gives them Scala-style, left-to-right, chainable operations:\n\n```go\nsum := seq.From([]int{1, 2, 3, 4, 5, 6}).\n    Filter(func(x int) bool { return x%2 == 0 }).\n    SumBy(func(x int) int { return x * x })\n```\n\n> ⚠️ **This library requires Go 1.27.** The chainable methods depend on the generic methods proposal ([golang\u002Fgo#77273](https:\u002F\u002Fgithub.com\u002Fgolang\u002Fgo\u002Fissues\u002F77273)), which **has been accepted** and is implemented in Go 1.27. A 1.27 toolchain (currently `go1.27rc1`) is required to build. See [Status](#status) below.\n\n## Why it exists\n\nToday, libraries like [`samber\u002Flo`](https:\u002F\u002Fgithub.com\u002Fsamber\u002Flo) can only offer top-level functions, so a pipeline reads inside-out:\n\n```go\n\u002F\u002F Reading order is the reverse of data flow: you start at the innermost Filter.\nsum := lo.Sum(\n    lo.Map(\n        lo.Filter([]int{1, 2, 3, 4, 5, 6}, func(x int, _ int) bool { return x%2 == 0 }),\n        func(x int, _ int) int { return x * x },\n    ),\n)\n```\n\nThis isn't a style preference — it's a language limitation. Before Go 1.27, **a method cannot declare its own type parameters**, so a `.Map()` that turns `Seq[int]` into `Seq[string]` is impossible to express:\n\n```go\n\u002F\u002F Pre-1.27: this does not compile. Methods may not have their own [U any].\nfunc (s Seq[T]) Map[U any](f func(T) U) Seq[U]\n```\n\n[golang\u002Fgo#77273](https:\u002F\u002Fgithub.com\u002Fgolang\u002Fgo\u002Fissues\u002F77273) lifts that restriction. Chainable, lazy, discoverable pipelines become possible — and that is the entire reason this library exists.\n\n## Design\n\n### Core types are *defined types*, not struct wrappers\n\n```go\ntype Seq[T any]      iter.Seq[T]       \u002F\u002F = func(yield func(T) bool)\ntype Seq2[K, V any]  iter.Seq2[K, V]\n```\n\nThis gives zero-cost conversion: any `iter.Seq[T]` can be used directly as a `Seq[T]` and vice versa, and the result feeds straight into `slices.Collect`, `maps.Keys`, etc. The cost is that `Seq[T]` declares `T` as `any` at the type level — and that single fact decides half the API.\n\n### The dividing rule: method vs. free function\n\nBecause `Seq[T any]` pins `T` to `any`, a method's type parameters are fresh and independent — **they cannot add a constraint back onto the receiver's `T`**. So:\n\n- Operations that constrain `T` itself **must be free functions**:\n\n  ```go\n  func Distinct[T comparable](s Seq[T]) Seq[T]\n  func Max[T cmp.Ordered](s Seq[T]) Optional[T]\n  func Sum[T Numeric](s Seq[T]) T\n  ```\n\n- Operations that only use a method's own constrained parameter **can be methods** (the \"escape hatch\"):\n\n  ```go\n  func (s Seq[T]) DistinctBy[K comparable](key func(T) K) Seq[T]\n  func (s Seq[T]) GroupBy[K comparable](key func(T) K) map[K][]T\n  ```\n\n- Operations over multiple generator types or a specific instantiation **must be free functions**:\n\n  ```go\n  func Zip[A, B any](a Seq[A], b Seq[B]) Seq2[A, B]   \u002F\u002F two independent types\n  func Flatten[T any](s Seq[Seq[T]]) Seq[T]           \u002F\u002F receiver must be Seq[Seq[T]]\n  ```\n\nThe rule is mechanically checkable: ask \"does it constrain `T` itself?\" If yes, it's a function; if no, it can be a method.\n\n## API at a glance\n\n| Group | Form | Examples |\n|-------|------|----------|\n| Constructors | free functions | `From`, `Of`, `Range`, `RangeStep`, `Repeat`, `Generate`, `Iterate`, `Times`, `FromChannel`, `FromMap` |\n| Intermediate (lazy) | methods | `Map`, `Filter`, `FlatMap`, `FilterMap`, `Reject`, `Take`\u002F`Drop`, `TakeWhile`\u002F`DropWhile`, `Scan`, `Chunk`, `Window`, `DistinctBy`, `Enumerate` |\n| Terminal | methods | `Collect`, `Fold`, `Reduce`, `Find`, `Any`\u002F`All`\u002F`None`, `GroupBy`, `KeyBy`, `Partition`, `SumBy`, `MaxByKey`, `Join` |\n| Grouping | free functions | `PartitionBy` (ordered groups as `Seq2[K,[]T]`) |\n| Constrained | free functions | `Distinct`, `Contains`, `Max`\u002F`Min`, `Sum`\u002F`Product`\u002F`Mean`, `Sort`, `Union`\u002F`Intersect`\u002F`Difference`, `Compact`, `Without` |\n| Constrained subtypes | functions (entry) + methods | `Comparable`\u002F`Ordered`\u002F`Numbers` enter; then chain `.Distinct()`, `.Max()`, `.Sum()`, `.Replace()`\u002F`.ReplaceAll()`; downgrade with `.Ordered()`\u002F`.Comparable()` |\n| Multi-sequence | free functions | `Zip`\u002F`Zip3`\u002F`Zip4`, `ZipWith`, `ZipMap`, `Unzip`, `Flatten`, `Concat`, `Interleave` |\n| `Seq2[K,V]` | methods + functions | `MapValues`, `MapKeys`, `Keys`, `Values`; `ToMap`, `CollectPairs`, `Associate` |\n| `Optional[T]` | type + methods + function | `Some`\u002F`None`\u002F`ToOptional`; `Get`, `Unwrap`\u002F`UnwrapOr`\u002F`OrElse`, `Map`, `Filter`, `FlatMap`; `MapOptional` (type-changing) |\n\nThe full, authoritative list with one-line semantics for each entry will live in `API.md`. The design rationale is in [`tasks\u002Fdesign-seq.md`](tasks\u002Fdesign-seq.md); the complete API inventory is in [`tasks\u002Fprd-seq-api-inventory.md`](tasks\u002Fprd-seq-api-inventory.md).\n\n### Optional[T]\n\n`Optional[T]` is the zero-dependency type used to express \"maybe no result\". The partial-result terminals — `Find`, `FindLast`, `First`, `Last`, `Nth`, `Reduce`, `MaxBy`\u002F`MinBy`\u002F`MaxByKey`\u002F`MinByKey`, the package-level `Max`\u002F`Min`, and the index-returning `FindIndex`\u002F`IndexOf`\u002F`LastIndexOf` (as `Optional[int]`) — all **return an `Optional` directly**, so you can chain post-processing without unpacking:\n\n```go\nout := s.Find(func(x int) bool { return x > 2 }).\n    Map(func(x int) int { return x * 10 }).\n    OrElse(-1)\n```\n\n`Seq2.Find` returns `Optional[Pair[K, V]]` (the key\u002Fvalue wrapped in a `Pair`). To drop back to Go's idiomatic `(value, ok)` pair, call `.Get()`:\n\n```go\nif v, ok := s.Max().Get(); ok { use(v) }\n```\n\n`ToOptional(v, ok)` bridges the other direction — wrapping a legacy `(value, ok)` pair into an `Optional`.\n\nBecause Go methods cannot introduce new type parameters, `Optional.Map` is same-type only; use the package-level `MapOptional[T, U]` to change the element type (e.g. `Optional[int]` → `Optional[string]`).\n\n## Scope\n\n**Not included** (by deliberate decision, see the design doc for the reasoning):\n\n- **Error-handling chains** (`Seq2[T, error]` short-circuiting) — no clean fit on Go's lazy iterators; deferred to a separate proposal.\n- **Parallel execution** (`lo\u002Fparallel`) — this version is sequential and lazy only.\n- **In-place mutation** (`lo\u002Fmutable`) — conflicts with the lazy, immutable model.\n- **Arbitrary-depth flatten** (`flattenDeep`) — Go's type system can't express it; only one-level `Flatten`.\n- **High-arity tuples** (`Tuple5`–`Tuple22`) — capped at `Tuple4`; use named structs for more fields.\n- **HKT \u002F type classes** and **generic methods satisfying interfaces** — the language doesn't support these.\n\n## Status\n\n**Draft.** The library requires **Go 1.27** (`go.mod` declares `go 1.27`); a 1.27 toolchain is needed to build, currently `go1.27rc1`. Work is split into two batches:\n\n- **Batch ① — core types and free functions** (`From`, `Distinct`, `Max`, `Zip`, …). Independently useful — effectively \"a `lo` with the correct constraint split\" — and compiles on Go 1.23+ if split out on its own.\n- **Batch ② — the chainable methods** (`Map`, `Filter`, `Fold`, …) that depend on Go 1.27 generic methods.\n\nThe generic methods proposal ([golang\u002Fgo#77273](https:\u002F\u002Fgithub.com\u002Fgolang\u002Fgo\u002Fissues\u002F77273)) has been accepted and is implemented in Go 1.27. The remaining gap is only that 1.27 is currently an RC, not yet a stable release; pinning the minimum version at 1.27 is the cost we accept for the method chain.\n\n## License\n\nSee [LICENSE](LICENSE).\n","这是一个为 Go 语言设计的泛型序列处理库，基于 Go 1.23+ 的标准库 iter.Seq，提供链式、惰性求值的集合操作接口。核心功能包括 Filter、Map、SumBy 等左向链式方法调用，依托 Go 1.27 引入的泛型方法特性实现类型安全的转换与组合；采用零开销类型别名设计（Seq[T] 直接定义为 iter.Seq[T]），兼容标准库迭代器生态。适用于需要简洁、可读性强且惰性执行的数据流处理场景，如 ETL 预处理、配置解析、API 响应转换等轻量级管道逻辑。",2,"2026-07-09 02:30:09","CREATED_QUERY"]