go-functional: iterators for Go, with a chainable variant
go-functional is a library of iterators to augment the standard library
At a glance
- What is it?
- BooleanCat's go-functional is a library of iterators built on Go's iter.Seq, and its most useful idea is the split into two packages, a plain one that returns values and a chainable one whose results can be chained with method calls, with the chaining form excluded from a handful of operations because Go's type system cannot express them.
- Who is it for?
- go-functional fits a Go developer who has moved to the range-over-func iterators and wants the collection and transformation helpers that the standard library does not have yet, especially the two-slice collection and the error-preserving collect. It does not fit a project on Go older than 1.23, because iter.Seq is the foundation of the whole library.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 44 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The two packages, and why there are two
go-functional is a library of iterators for use with iter.Seq and it requires Go 1.23 or newer. Most functions offered by the package are either consumers or iterators, and the split is the standard one: consumers iterate over an iterator and completely or partially drain them of values, collecting the values into a data type in most cases, while iterators are functions that yield new values and can be ranged over. The package provides two flavours, the it package and the itx package, and the difference is what each call returns. The plain it functions take an iterator and give you a value, while the itx functions take an iterator and give you something you can call methods on. The project describes the standard library as providing functions to collect iterators in the slices and maps packages that should satisfy most cases where collection is needed, and this package adds collection methods and makes the existing standard library consumers chainable. The type parameter is the reason for the split, and the package notes repeat it: the itx package does not contain All, Any, TryCollect, MustCollect, Fold, Max or Min due to limitations with Go's type system.
Installing it, and the shape of the API
The install is a module fetch.
go get github.com/BooleanCat/go-functional/v2@latestThe examples at the top of the documentation show the shape of the API, with a slice of the first five natural numbers, the even numbers, and the string representations of integers.
// The first 5 natural numbers
numbers := slices.Collect(
it.Take(it.NaturalNumbers[int](), 5),
)
// All even numbers
evens := it.Filter(it.NaturalNumbers[int](), filter.IsEven)
// String representations of integers
numbers := it.Map(it.NaturalNumbers[int](), strconv.Itoa)The package is MIT licensed, the module path carries a v2 major version, and the reference documentation is published on pkg.go.dev. The most recent release is v2.6.0 on 2026-09-09, and the last push to the repository was the same day, with v2.5.1 from April 2025 before it.
The plain consumers, and the infinite iterator trap
The consumers are the part you will use every day, and the first one to know is a warning that applies to all of them. Attempting to collect infinite iterators will cause an infinite loop and likely deadlock, so consider bounding infinite iterators before collect, for example using Take. All returns true if all the values yielded by an iterator are true and false otherwise, terminating early if false is encountered, and returning true for an empty iterator. Any is the mirror image, terminating early on true and returning false for an empty iterator. Collect has several variants, and the ones for two-value iterators are the ones the standard library does not provide, since it.Collect2 collects an iter.Seq2 into two slices, and the chainable form does the same from a map.
// Chainable
numbers := itx.NaturalNumbers[int]().Take(5).Collect()
// Collect an iter.Seq2[V, W] into two slices
keys, values := it.Collect2(maps.All(map[string]int{"one": 1, "two": 2}))Fold is the accumulator form, and it too has a two-value variant, with the op package holding some simple pre-defined operation functions. Len counts the values yielded, with a separate Len2 for the two-value case. Max and Min consume an iterator and return the maximum or minimum value with a boolean saying whether the iterator held at least one value, and the value type must be comparable.
Error handling inside an iterator
The most interesting consumer is the one that deals with iterators that yield a value and an error, because the boilerplate of checking every element for a non-nil error is exactly what the package removes. TryCollect solves it by collecting all values into a slice and returning a single error, the first one encountered.
text := strings.NewReader("one\ntwo\nthree\n")
if lines, err := it.TryCollect(it.LinesString(text)); err != nil {
fmt.Println(lines)
}MustCollect is similar except that if an error is encountered a panic will occur, and the project recommends it when you can guarantee that no error will occur, as with a strings.Reader. Two notes apply to both. If an error is encountered, collection stops, which means the iterator being collected may not be fully drained, and neither TryCollect nor MustCollect is in the chainable itx package, again because of the type system. The distinction between the two is a real design decision rather than an inconsistency, since a panic in a library function is the kind of thing you want to choose deliberately.
ForEach, and the enumerated form
ForEach consumes an iterator and applies a function to each value yielded, and it has a two-value variant that gives the index and the value, which is what you want when the position matters. The chainable package offers the same thing with an Enumerate step in the middle, which is the idiomatic way to get an index out of a plain sequence. The reason the chainable variant exists at all is that a method call on a value reads better in a pipeline than a function call with the iterator as an argument, and once you have one iterator in a chain the whole chain wants to be a chain.
it.ForEach(slices.Values([]int{1, 2, 3}), func(number int) {
fmt.Println(number)
})
// Chainable
itx.FromSlice([]int{1, 2, 3}).ForEach(func(number int) {
fmt.Println(number)
})Find consumes an iterator until a value is found that satisfies a predicate, returning the value and true if one was found, and it sits in the same family as the other consumers. The whole consumer set shares a shape, and the type parameter is threaded through all of it, which is what the itx limitations come from.
How the project checks itself
The Makefile is the whole build and test story, and it is worth reading for what it does and does not cover. The check target depends on lint, runs go vet over everything, then lists the files gofmt would change and fails if that list is not empty, so formatting is enforced rather than suggested. The lint target runs golangci-lint, and it can be skipped with the SKIP_LINT variable defined. Tests run with the race detector and verbose output, and the coverage target runs the same race-enabled tests with a coverprofile and the atomic cover mode, excluding the assert and fakes packages from the package list. The repository is Go 1.23 in its go.mod, with no dependencies listed, and it carries a .golangci.yml, a .prettierrc for the Markdown, a code of conduct, a security policy and a contributing guide. The README also badges the Go report card, codecov and the pkg.go.dev reference, so the coverage and static analysis signals are visible on the project page.
Editorial conclusion
go-functional fits a Go developer who has moved to the range-over-func iterators and wants the collection and transformation helpers that the standard library does not have yet, especially the two-slice collection and the error-preserving collect. It does not fit a project on Go older than 1.23, because iter.Seq is the foundation of the whole library. It also does not fit a developer who expects a uniform API, because the chainable package is deliberately missing All, Any, TryCollect, MustCollect, Fold, Max and Min for type system reasons, and the two packages must be used side by side rather than interchangeably. Before you adopt it, decide which of the two packages each call site needs, since the chainable form is the one you will reach for and the plain one is the one you will fall back to.
Frequently asked questions
What is go-functional and what does it require?
It is a library of iterators for use with iter.Seq, and it requires Go 1.23 or newer. It provides consumers that drain an iterator and iterators that yield new values, and it comes in two packages, a plain one and a chainable one.
Why does the chainable itx package not have All, Any, Fold, Max or Min?
Because of limitations with Go's type system, as the package notes state repeatedly. The same reason keeps TryCollect and MustCollect out of itx, since a chainable receiver cannot express the error-returning form.
How do I collect an iterator that can return errors?
Use TryCollect, which collects all values into a slice and returns a single error, the first one encountered, or MustCollect, which panics if an error is encountered. The project recommends MustCollect when no error can occur, and notes that collection stops at the first error, so the iterator may not be fully drained.
How do I install go-functional?
With go get github.com/BooleanCat/go-functional/v2@latest, and the reference documentation is published on pkg.go.dev. The module is MIT licensed and the current release is v2.6.0.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/booleancat-go-functional)Was this useful?