Gust
A production-ready library that makes error handling, optional values, and iteration as beautiful and safe as in Rust.
Install / Use
/learn @andeya/GustREADME
gust 🌬️
Write Go code that's as safe as Rust, as expressive as functional programming, and as fast as native Go.
A zero-dependency library that brings Rust's most powerful patterns to Go, eliminating error boilerplate, nil panics, and imperative loops.
</div>🎯 What is gust?
gust is a production-ready Go library that brings Rust's most powerful patterns to Go. It transforms how you write Go code by providing:
- Type-safe error handling with
Result[T]- eliminateif err != nilboilerplate - Safe optional values with
Option[T]- no more nil pointer panics - Declarative iteration with 60+ iterator methods - write data pipelines like Rust
With zero dependencies and full type safety, gust lets you write Go code that's safer, cleaner, and more expressive—without sacrificing performance.
✨ The Catch Pattern: gust's Secret Weapon
gust introduces the result.Ret + Unwrap + Catch pattern—a revolutionary way to handle errors in Go:
func fetchUserData(userID int) (r result.Result[string]) {
defer r.Catch() // One line handles ALL errors!
user := result.Ret(db.GetUser(userID)).Unwrap()
profile := result.Ret(api.GetProfile(user.Email)).Unwrap()
return result.Ok(fmt.Sprintf("%s: %s", user.Name, profile.Bio))
}
One line (defer r.Catch()) eliminates all if err != nil checks. Errors automatically propagate via panic and are caught, converted to Result, and returned.
✨ Why gust?
| Traditional Go | With gust |
|----------------|-----------|
| ❌ 15+ lines of error checks | ✅ 3 lines with Catch pattern |
| ❌ if err != nil everywhere | ✅ defer r.Catch() once |
| ❌ Nil pointer panics | ✅ Compile-time safety |
| ❌ Imperative loops | ✅ Declarative pipelines |
| ❌ Hard to compose | ✅ Elegant method chaining |
🚀 Quick Start
go get github.com/andeya/gust
Your First gust Program (with Catch Pattern)
package main
import (
"fmt"
"github.com/andeya/gust/result"
)
func main() {
// Using Catch pattern - errors flow automatically!
processValue := func(value int) (r result.Result[int]) {
defer r.Catch()
doubled := value * 2
if doubled > 20 {
return result.TryErr[int]("too large")
}
return result.Ok(doubled + 5)
}
res := processValue(10)
if res.IsOk() {
fmt.Println("Success:", res.Unwrap())
} else {
fmt.Println("Error:", res.UnwrapErr())
}
}
Output: Success: 25
💡 The Problem gust Solves
Before: Traditional Go Code (15+ lines, 4 error checks)
func fetchUserData(userID int) (string, error) {
user, err := db.GetUser(userID)
if err != nil {
return "", fmt.Errorf("db error: %w", err)
}
if user == nil {
return "", fmt.Errorf("user not found")
}
if user.Email == "" {
return "", fmt.Errorf("invalid user: no email")
}
profile, err := api.GetProfile(user.Email)
if err != nil {
return "", fmt.Errorf("api error: %w", err)
}
if profile == nil {
return "", fmt.Errorf("profile not found")
}
return fmt.Sprintf("%s: %s", user.Name, profile.Bio), nil
}
Problems:
- ❌ 4 repetitive
if err != nilchecks - ❌ 3 nested conditionals
- ❌ Hard to test individual steps
- ❌ Easy to forget error handling
- ❌ 15+ lines of boilerplate
After: With gust Catch Pattern (8 lines, 0 error checks)
import "github.com/andeya/gust/result"
func fetchUserData(userID int) (r result.Result[string]) {
defer r.Catch() // One line handles ALL errors!
user := result.Ret(db.GetUser(userID)).Unwrap()
if user == nil || user.Email == "" {
return result.TryErr[string]("invalid user")
}
profile := result.Ret(api.GetProfile(user.Email)).Unwrap()
if profile == nil {
return result.TryErr[string]("profile not found")
}
return result.Ok(fmt.Sprintf("%s: %s", user.Name, profile.Bio))
}
Benefits:
- ✅ One line error handling -
defer r.Catch()handles everything - ✅ Linear flow - Easy to read top-to-bottom
- ✅ Automatic propagation - Errors stop execution automatically
- ✅ Composable - Each step is independent and testable
- ✅ Type-safe - Compiler enforces correct error handling
- ✅ 70% less code - From 15+ lines to 8 lines
📚 Core Features
1. Result<T> - The Catch Pattern Revolution
The Catch pattern (result.Ret + Unwrap + Catch) is gust's most powerful feature:
import "github.com/andeya/gust/result"
// Before: Traditional Go (multiple error checks)
// func readConfig(filename string) (string, error) {
// f, err := os.Open(filename)
// if err != nil {
// return "", err
// }
// defer f.Close()
// data, err := io.ReadAll(f)
// if err != nil {
// return "", err
// }
// return string(data), nil
// }
// After: gust Catch pattern (linear flow, no error checks)
func readConfig(filename string) (r result.Result[string]) {
defer r.Catch() // One line handles ALL errors!
data := result.Ret(os.ReadFile(filename)).Unwrap()
return result.Ok(string(data))
}
Key Methods:
result.Ret(T, error)- Convert(T, error)toResult[T]Unwrap()- Extract value (panics if error, caught byCatch)defer r.Catch()- Catch all panics and convert toResulterrorsMap- Transform value if OkAndThen- Chain operations returning ResultUnwrapOr- Extract safely with default (never panics)
Real-World Use Cases:
- API call chains
- Database operations
- File I/O operations
- Data validation pipelines
2. Option<T> - No More Nil Panics
Replace *T and (T, bool) with safe Option[T] that prevents nil pointer panics:
import "github.com/andeya/gust/option"
// Before: Traditional Go (nil checks everywhere)
// func divide(a, b float64) *float64 {
// if b == 0 {
// return nil
// }
// result := a / b
// return &result
// }
// result := divide(10, 2)
// if result != nil {
// fmt.Println(*result * 2) // Risk of nil pointer panic
// }
// After: gust Option (type-safe, no nil panics)
divide := func(a, b float64) option.Option[float64] {
if b == 0 {
return option.None[float64]()
}
return option.Some(a / b)
}
quotient := divide(10, 2).
Map(func(x float64) float64 { return x * 2 }).
UnwrapOr(0) // Safe: never panics
fmt.Println(quotient) // 10
Key Methods:
Map- Transform value if SomeAndThen- Chain operations returning OptionFilter- Conditionally filter valuesUnwrapOr- Extract safely with default (never panics)
Real-World Use Cases:
- Configuration reading
- Optional function parameters
- Map lookups
- JSON unmarshaling
3. Iterator - Rust-like Iteration
Full Rust Iterator trait implementation with 60+ methods for declarative data processing:
import "github.com/andeya/gust/iterator"
// Before: Traditional Go (nested loops, manual error handling)
// func processNumbers(input []string) ([]int, error) {
// var results []int
// for _, s := range input {
// n, err := strconv.Atoi(s)
// if err != nil {
// continue
// }
// if n > 0 {
// results = append(results, n*2)
// }
// }
// return results, nil
// }
// After: gust Iterator (declarative, type-safe, 70% less code)
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]
Highlights:
- 🚀 60+ methods from Rust's Iterator trait
- 🔄 Lazy evaluation - Computations happen on-demand
- 🔗 Method chaining - Compose complex operations elegantly
- 🔌 Go 1.24+ integration - Works with standard
iter.Seq[T] - 🎯 Type-safe - Compile-time guarantees
- ⚡ Zero-cost abstractions - No performance overhead
Method Categories:
- Constructors:
FromSlice,FromRange,FromFunc,Empty,Once,Repeat - BitSet Iterators:
FromBitSet,FromBitSetOnes,FromBitSetZeros - Go Integration:
FromSeq,Seq,Pull(Go 1.24+ standard iterators) - Basic Adapters:
Map,Filter,Chain,Zip,Enumerate - Filtering:
Skip,Take,StepBy,SkipWhile,TakeWhile - Transforming:
MapWhile,Scan,FlatMap,Flatten - Chunking:
MapWindows,ArrayChunks,ChunkBy - Consumers:
Collect,Fold,Reduce,Count,Sum,Product,Partition - Search:
Find,FindMap,Position,All,Any - Min/Max:
Max,Min,MaxBy,MinBy,MaxByKey,MinByKey - Double-Ended:
NextBack,Rfold,Rfind,NthBack
🌟 Real-World Examples
Example 1: Data Processing Pipeline (Iterator + Result)
Before: Traditional Go (nested loops + error handling, 15+ lines)
func pro
