π― What is gust?
gust is a comprehensive Go library that brings Rust's most powerful patterns to Go, enabling you to write safer, cleaner, and more expressive code. With zero dependencies and production-ready quality, gust transforms how you handle errors, optional values, and data iteration in Go.
β¨ Key Features
- π‘οΈ Type-Safe Error Handling - Replace
(T, error) with chainable Result[T]
- π― No More Nil Panics - Use
Option[T] instead of *T or (T, bool)
- π Rust-like Iterators - Full Iterator trait implementation with 60+ methods
- β‘ Zero Dependencies - Pure Go, no external dependencies
- π Well Documented - Comprehensive docs with real-world examples
- π Production Ready - High test coverage and battle-tested
π Quick Start
go get github.com/andeya/gust
Your First gust Program
package main
import (
"fmt"
"github.com/andeya/gust/result"
)
func main() {
// Chain operations elegantly
res := result.Ok(10).
Map(func(x int) int { return x * 2 }).
AndThen(func(x int) result.Result[int] {
if x > 20 {
return result.TryErr[int]("too large")
}
return result.Ok(x + 5)
})
if res.IsOk() {
fmt.Println("Success:", res.Unwrap())
} else {
fmt.Println("Error:", res.UnwrapErr())
}
}
π‘ Why gust?
The Problem with Traditional Go
Traditional Go code is verbose and error-prone:
func fetchUserData(userID int) (string, error) {
// Step 1: Fetch from database
user, err := db.GetUser(userID)
if err != nil {
return "", fmt.Errorf("db error: %w", err)
}
// Step 2: Validate user
if user == nil {
return "", fmt.Errorf("user not found")
}
if user.Email == "" {
return "", fmt.Errorf("invalid user: no email")
}
// Step 3: Fetch profile
profile, err := api.GetProfile(user.Email)
if err != nil {
return "", fmt.Errorf("api error: %w", err)
}
// Step 4: Format result
return fmt.Sprintf("%s: %s", user.Name, profile.Bio), nil
}
Issues:
- β Repetitive error handling boilerplate
- β Nested if-else statements
- β Hard to compose and test
- β Easy to forget error checks
The gust Solution
With gust, write declarative, composable code:
import "github.com/andeya/gust/result"
func fetchUserData(userID int) result.Result[string] {
return result.AndThen(result.Ret(getUser(userID)), func(user *User) result.Result[string] {
if user == nil || user.Email == "" {
return result.TryErr[string]("invalid user")
}
return result.Map(result.Ret(getProfile(user.Email)), func(profile *Profile) string {
return fmt.Sprintf("%s: %s", user.Name, profile.Bio)
})
})
}
Benefits:
- β
No error boilerplate - Errors flow naturally through the chain
- β
Linear flow - Easy to read and understand
- β
Automatic propagation - Errors stop the chain automatically
- β
Composable - Each step is independent and testable
- β
Type-safe - Compiler enforces correct error handling
From Imperative to Declarative
gust helps you shift from imperative (focusing on how) to declarative (focusing on what) programming:

With gust, you describe what you want to achieve, not how to achieve it step-by-step. This makes your code more readable, maintainable, and less error-prone.
π Core Features
1. Result - Elegant Error Handling
Replace (T, error) with chainable Result[T] for type-safe error handling:
import "github.com/andeya/gust/result"
// Chain operations that can fail
res := result.Ok(10).
Map(func(x int) int { return x * 2 }).
AndThen(func(x int) result.Result[int] {
if x > 15 {
return result.TryErr[int]("too large")
}
return result.Ok(x + 5)
}).
OrElse(func(err error) result.Result[int] {
fmt.Println("Error handled:", err)
return result.Ok(0) // Fallback
})
fmt.Println("Final value:", res.Unwrap())
// Output: Error handled: too large
// Final value: 0
Key Methods:
Map - Transform the value if Ok
AndThen - Chain operations that return Result
OrElse - Handle errors with fallback
Unwrap / UnwrapOr - Extract values safely
IsOk / IsErr - Check result state
Benefits:
- β
No more
if err != nil boilerplate
- β
Automatic error propagation
- β
Chain multiple operations elegantly
- β
Type-safe error handling
2. Option - No More Nil Panics
Replace *T and (T, bool) with safe Option[T]:
import "github.com/andeya/gust/option"
// Safe division without nil checks
divide := func(a, b float64) option.Option[float64] {
if b == 0 {
return option.None[float64]()
}
return option.Some(a / b)
}
res := divide(10, 2).
Map(func(x float64) float64 { return x * 2 }).
UnwrapOr(0)
fmt.Println(res) // 10
Key Methods:
Map - Transform the value if Some
AndThen - Chain operations that return Option
Filter - Conditionally filter values
Unwrap / UnwrapOr - Extract values safely
IsSome / IsNone - Check option state
Benefits:
- β
Eliminates nil pointer panics
- β
Explicit optional values
- β
Chain operations safely
- β
Compiler-enforced safety
3. Iterator - Rust-like Iteration in Go
Full Rust Iterator trait implementation with method chaining and lazy evaluation:
import "github.com/andeya/gust/iterator"
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
sum := iterator.FromSlice(numbers).
Filter(func(x int) bool { return x%2 == 0 }).
Map(func(x int) int { return x * x }).
Take(3).
Fold(0, func(acc int, x int) int {
return acc + x
})
fmt.Println(sum) // 56 (4 + 16 + 36)
Available Methods:
| Category |
Methods |
| Constructors |
FromSlice, FromElements, FromRange, FromFunc, FromIterable, Empty, Once, Repeat |
| BitSet Iterators |
FromBitSet, FromBitSetOnes, FromBitSetZeros, FromBitSetBytes, etc. |
| Go Integration |
FromSeq, FromSeq2, FromPull, FromPull2, Seq, Seq2, Pull, Pull2 |
| Basic Adapters |
Map, FilterMap, RetMap, OptMap, Chain, Zip, Enumerate |
| Filtering Adapters |
Filter, Skip, Take, StepBy, SkipWhile, TakeWhile |
| Transforming Adapters |
MapWhile, Scan, FlatMap, Flatten |
| Chunking Adapters |
MapWindows, ArrayChunks, ChunkBy |
| Utility Adapters |
Fuse, Inspect, Intersperse, IntersperseWith, Cycle, Peekable |
| Consumers |
Fold, Reduce, Collect, Count, Last, All, Any, Find, Sum, Product, Partition, AdvanceBy, Nth, NextChunk |
| Search & Find |
Find, FindMap, Position, All, Any |
| Min/Max |
Max, Min, MaxBy, MinBy, MaxByKey, MinByKey |
| Try Methods |
TryFold, TryForEach, TryReduce, TryFind |
| Double-Ended |
NextBack, Rfold, TryRfold, Rfind, AdvanceBackBy, NthBack |
60+ methods from Rust's Iterator trait!
Code Organization:
The iterator package is organized into functional modules for better maintainability:
- Core (
core.go): Core interfaces (Iterable, Iterator, DoubleEndedIterator) and base types, including double-ended methods (NextBack, AdvanceBackBy, NthBack, Remaining)
- Constructors (
constructors.go): Functions to create iterators from various sources
- Basic Adapters (
basic.go): Map, FilterMap, Chain, Zip, Enumerate, FlatMap
- Filtering Adapters (
filtering.go): Skip, Take, StepBy, SkipWhile, TakeWhile
- Transforming Adapters (
transforming.go): MapWhile, Scan, Flatten
- Chunking Adapters (
chunking.go): MapWindows, ArrayChunks, ChunkBy
- Utility Adapters (
utility.go): Fuse, Inspect, Intersperse, IntersperseWith, Cycle, Peekable, Cloned
- Consumers (
consumers.go): Collect, Count, Last, Partition, AdvanceBy, Nth, NextChunk, Sum, Product, Unzip, TryReduce, TryForEach
- Fold & Reduce (
fold_reduce.go): Fold, Reduce, ForEach, TryFold, Rfold, TryRfold
- Find & Search (
find_search.go): Find, FindMap, Position, All, Any, TryFind, Rfind
- Min & Max (
min_max.go): Max, Min, MaxBy, MinBy, MaxByKey, MinByKey
- Comparison (
comparison.go): Comparison utilities
Each module is self-contained with its own implementation functions (_Impl) and iterable structs (_Iterable), ensuring independence and maintainability. Double-ended iterator methods are integrated into their respective functional modules (e.g., Rfold in fold_reduce.go, Rfind in find_search.go).
Note: For type-changing operations (e.g., Map from string to int), use the function-style API:
iterator.Map(iterator.FromSlice(strings), func(s string) int { return len(s) })
For same-type operations, you can use method chaining:
iterator.FromSlice(numbers).
Filter(func(x int) bool { return x > 0 }).
Map(func(x int) int { return x * 2 })
Benefits:
- β
Rust-like method chaining
- β
Lazy evaluation
- β
Type-safe transformations
- β
Zero-copy where possible
Iterator Constructors
Create iterators from various sources:
import (
"github.com/andeya/gust/iterator"
"github.com/andeya/gust/option"
)
// From slice
iter1 := iterator.FromSlice([]int{1, 2, 3})
// From individual elements
iter2 := iterator.FromElements(1, 2, 3)
// From range [start, end)
iter3 := iterator.FromRange(0, 5) // 0, 1, 2, 3, 4
// From function
count := 0
iter4 := iterator.FromFunc(func() option.Option[int] {
if count < 3 {
count++
return option.Some(count)
}
return option.None[int]()
})
// Empty iterator
iter5 := iterator.Empty[int]()
// Single value
iter6 := iterator.Once(42)
// Infinite repeat
iter7 := iterator.Repeat("hello") // "hello", "hello", "hello", ...
Go Standard Iterator Integration
gust iterators seamlessly integrate with Go 1.24+ standard iterators:
Convert gust Iterator to Go's iter.Seq[T]:
import "github.com/andeya/gust/iterator"
numbers := []int{1, 2, 3, 4, 5}
gustIter := iterator.FromSlice(numbers).Filter(func(x int) bool { return x%2 == 0 })
// Use in Go's standard for-range loop
for v := range gustIter.Seq() {
fmt.Println(v) // prints 2, 4
}
Convert Go's iter.Seq[T] to gust Iterator:
import "github.com/andeya/gust/iterator"
// Create a Go standard iterator sequence
goSeq := func(yield func(int) bool) {
for i := 0; i < 5; i++ {
if !yield(i) {
return
}
}
}
// Convert to gust Iterator and use gust methods
gustIter, deferStop := iterator.FromSeq(goSeq)
defer deferStop()
result := gustIter.Map(func(x int) int { return x * 2 }).Collect()
fmt.Println(result) // [0 2 4 6 8]
4. Double-Ended Iterator
Iterate from both ends efficiently:
import "github.com/andeya/gust/iterator"
numbers := []int{1, 2, 3, 4, 5}
deIter := iterator.FromSlice(numbers).MustToDoubleEnded()
// Iterate from front
if val := deIter.Next(); val.IsSome() {
fmt.Println("Front:", val.Unwrap()) // Front: 1
}
// Iterate from back
if val := deIter.NextBack(); val.IsSome() {
fmt.Println("Back:", val.Unwrap()) // Back: 5
}
π Real-World Examples
Parse and Filter with Error Handling
import (
"github.com/andeya/gust/iterator"
"github.com/andeya/gust/result"
"strconv"
)
// Parse strings to integers, automatically filtering out errors
numbers := []string{"1", "2", "three", "4", "five"}
results := iterator.FilterMap(
iterator.RetMap(iterator.FromSlice(numbers), strconv.Atoi),
result.Result[int].Ok,
).Collect()
fmt.Println("Parsed numbers:", results)
// Output: Parsed numbers: [1 2 4]
Data Processing Pipeline
import (
"github.com/andeya/gust/iterator"
"github.com/andeya/gust/result"
"strconv"
)
// Process user input: parse, validate, transform, limit
input := []string{"10", "20", "invalid", "30", "0", "40"}
results := iterator.FilterMap(
iterator.RetMap(iterator.FromSlice(input), strconv.Atoi),
result.Result[int].Ok,
).
Filter(func(x int) bool { return x > 0 }).
Map(func(x int) int { return x * 2 }).
Take(3).
Collect()
fmt.Println(results) // [20 40 60]
Option Chain Operations
import (
"fmt"
"github.com/andeya/gust/option"
)
// Chain operations on optional values with filtering
res := option.Some(5).
Map(func(x int) int { return x * 2 }).
Filter(func(x int) bool { return x > 8 }).
XMap(func(x int) any {
return fmt.Sprintf("Value: %d", x)
}).
UnwrapOr("No value")
fmt.Println(res) // "Value: 10"
Partition Data
import (
"fmt"
"github.com/andeya/gust/iterator"
)
// Split numbers into evens and odds
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
evens, odds := iterator.FromSlice(numbers).
Partition(func(x int) bool { return x%2 == 0 })
fmt.Println("Evens:", evens) // [2 4 6 8 10]
fmt.Println("Odds:", odds) // [1 3 5 7 9]
BitSet Iteration
Iterate over bits in bit sets or byte slices with full iterator support:
import (
"fmt"
"github.com/andeya/gust/iterator"
)
// Iterate over bits in a byte slice
bytes := []byte{0b10101010, 0b11001100}
// Get all set bit offsets
setBits := iterator.FromBitSetBytesOnes(bytes).
Filter(func(offset int) bool { return offset > 5 }).
Collect()
fmt.Println(setBits) // [6 8 9 12 13]
// Count set bits
count := iterator.FromBitSetBytesOnes(bytes).Count()
fmt.Println(count) // 8
// Sum of offsets of set bits
sum := iterator.FromBitSetBytesOnes(bytes).
Fold(0, func(acc, offset int) int { return acc + offset })
fmt.Println(sum) // 54 (0+2+4+6+8+9+12+13)
π¦ Additional Packages
gust provides several utility packages to extend its functionality:
| Package |
Description |
gust/dict |
Generic map utilities (Filter, Map, Keys, Values, Get, etc.) |
gust/vec |
Generic slice utilities (MapAlone, Get, Copy, Dict, etc.) |
gust/conv |
Type-safe value conversion and reflection utilities |
gust/digit |
Number conversion utilities (base conversion, FormatByDict, ParseByDict) |
gust/opt |
Helper functions for Option[T] (Map, AndThen, Zip, Unzip, Assert) |
gust/result |
Helper functions for Result[T] (Map, AndThen, Assert, Flatten) |
gust/iterator |
Rust-like iterator implementation (see Iterator section) |
gust/syncutil |
Concurrent utilities (SyncMap, Mutex wrappers, Lazy initialization) |
gust/errutil |
Error utilities (Stack traces, Panic recovery, ErrBox) |
gust/constraints |
Type constraints (Ordering, Numeric, etc.) |
Quick Examples
Dict utilities:
import "github.com/andeya/gust/dict"
m := map[string]int{"a": 1, "b": 2, "c": 3}
value := dict.Get(m, "b").UnwrapOr(0) // 2
filtered := dict.Filter(m, func(k string, v int) bool { return v > 1 })
Vec utilities:
import "github.com/andeya/gust/vec"
numbers := []int{1, 2, 3, 4, 5}
doubled := vec.MapAlone(numbers, func(x int) int { return x * 2 })
SyncUtil utilities:
import "github.com/andeya/gust/syncutil"
// Thread-safe map
var m syncutil.SyncMap[string, int]
m.Store("key", 42)
value := m.Load("key") // Returns Option[int]
// Lazy initialization
lazy := syncutil.NewLazy(func() int {
return expensiveComputation()
})
value := lazy.Get() // Computed only once
For more details, see the full documentation and examples.
π Resources
π Requirements
- Go 1.24+ (required for generics and standard iterator support)
π€ Contributing
We welcome contributions! Whether you're:
- π Reporting bugs - Help us improve by reporting issues
- π‘ Suggesting features - Share your ideas for new features
- π Improving docs - Help make our documentation better
- π§ Submitting PRs - Contribute code improvements
Every contribution makes gust better! Please see our Contributing Guidelines (if available) or feel free to submit a Pull Request or open an issue.
Development Setup
# Clone the repository
git clone https://github.com/andeya/gust.git
cd gust
# Run tests
go test ./...
# Run tests with coverage
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
π License
This project is licensed under the MIT License - see the LICENSE file for details.