result

package
v2.0.0-alpha.19 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 6, 2025 License: MIT Imports: 17 Imported by: 14

README

Result Module

The result module provides functional programming-inspired error handling through Result[T] and Error types. It eliminates explicit nil checks and enables safe, composable error handling with method chaining.

Features

  • Type-Safe Error Handling: Eliminate nil-check bugs with generic Result types
  • Method Chaining: Fluent API for transforming and combining operations
  • Pattern Matching: Exhaustive error handling with Match functions
  • Async Support: Future types for asynchronous computations
  • Standard Compatibility: Works with existing Go error handling patterns

Installation

go get github.com/pubgo/funk/v2/result

Quick Start

Basic Usage
import "github.com/pubgo/funk/v2/result"

// Create successful result
success := result.OK(42)

// Create failed result
failure := result.Fail[int](errors.New("calculation failed"))

// Safe unwrapping
if value, ok := success.TryUnwrap(); ok {
    fmt.Printf("Value: %d\n", value)
}

// Method chaining
processed := result.OK("hello").
    Map(strings.ToUpper).
    FlatMap(func(s string) result.Result[string] {
        if len(s) > 0 {
            return result.OK(s + " world")
        }
        return result.Fail[string](errors.New("empty string"))
    })
Error Handling
// Pattern matching
result.OK(42).Match(
    func(value int) { fmt.Printf("Success: %d\n", value) },
    func(err error) { fmt.Printf("Error: %v\n", err) }
)

// Error-only operations
result.ErrOf(errors.New("something went wrong")).
    Log().
    InspectErr(func(err error) { 
        // Additional error processing
    })

Core Concepts

Result[T]

Result[T] represents either a successful value of type T or an error. It provides a safe alternative to returning (T, error) pairs.

Creation Functions
  • OK(v T): Create successful result
  • Fail[T](err error): Create failed result
  • Wrap(v T, err error): Create result from value/error pair
  • WrapFn(fn func() (T, error)): Create result from function
Transformation Methods
  • Map(func(T) T): Transform successful value
  • FlatMap(func(T) Result[T]): Transform with potential for new errors
  • Validate(func(T) error): Validate value with potential error
  • Or(default T): Provide fallback value for errors
Consumption Methods
  • Unwrap(): Get value or panic on error
  • TryUnwrap(): Safely get value with success indicator
  • UnwrapOr(default T): Get value or default on error
  • Expect(msg string): Get value or panic with custom message
Error

Error is a specialized result type for error-only operations, providing utilities for error handling and logging.

Creation Functions
  • ErrOf(err error): Create from error
  • ErrOfFn(fn func() error): Create from error-returning function
  • Errorf(format string, args ...any): Create formatted error
Error Handling Methods
  • Log(): Log error with stack trace
  • InspectErr(func(error)): Process error without consuming it
  • Match(func(), func(error)): Pattern match on error presence
Future[T]

Future[T] represents asynchronous computations that will eventually produce a Result[T].

Creation Functions
  • Async(fn func() Result[T]): Create from async function
  • AsyncErr(fn func() Error): Create from async error function
Usage
// Start async computation
future := result.Async(func() result.Result[int] {
    // Simulate work
    time.Sleep(time.Second)
    return result.OK(42)
})

// Wait for result
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

result := future.Await(ctx)

Advanced Usage

Chaining Operations
// Complex transformation pipeline
result := getUser(id).
    FlatMap(validateUser).
    Map(encryptUserData).
    FlatMap(saveUser).
    Inspect(func(savedUser User) {
        log.Info().Msgf("User saved: %s", savedUser.ID)
    }).
    MapErr(func(err error) error {
        return fmt.Errorf("failed to process user: %w", err)
    })
Working with Collections
// Process multiple results
results := []result.Result[int]{
    result.OK(1),
    result.OK(2),
    result.Fail[int](errors.New("conversion failed")),
    result.OK(4),
}

// Collect all successful values or first error
collected := result.Collect(results)
values, err := collected.UnwrapErr()

// Partition into successes and failures
successes, failures := result.Partition(results)
Pattern Matching
// Exhaustive error handling
result.OK(42).Match(
    func(value int) {
        fmt.Printf("Success: %d\n", value)
    },
    func(err error) {
        fmt.Printf("Error: %v\n", err)
    }
)

// Result-producing pattern matching
result.OK(42).MatchWithResult(
    func(value int) result.Result[string] {
        return result.OK(strconv.Itoa(value))
    },
    func(err error) result.Result[string] {
        return result.Fail[string](err)
    }
)

Integration Patterns

With Standard Error Handling
// Convert from standard (T, error) pattern
func divide(a, b float64) result.Result[float64] {
    if b == 0 {
        return result.Fail[float64](errors.New("division by zero"))
    }
    return result.OK(a / b)
}

// Convert to standard (T, error) pattern
value, err := divide(10, 2).UnwrapErr()
With Context
// Context-aware operations
func fetchUser(ctx context.Context, id string) result.Result[User] {
    user, err := database.GetUser(ctx, id)
    return result.Wrap(user, err)
}

// Async with context
future := result.Async(func() result.Result[User] {
    return fetchUser(ctx, userID)
})

result := future.Await(ctx)

Best Practices

  1. Prefer Result[T] over (T, error): For better composability and fewer nil checks
  2. Use TryUnwrap for Safe Extraction: Avoid panics in uncertain situations
  3. Chain Operations for Readability: Use Map/FlatMap for data transformation pipelines
  4. Handle Errors Appropriately: Use Match for exhaustive error handling
  5. Leverage Async for IO-bound Operations: Use Future[T] for non-blocking computations

API Reference

Result[T] Creation
Function Description
OK(v T) Create successful result
Fail[T](err error) Create failed result
Wrap(v T, err error) Create from value/error pair
WrapFn(fn func() (T, error)) Create from function
Result[T] Inspection
Method Description
IsOK() bool Check if result is successful
IsErr() bool Check if result is error
TryUnwrap() (T, bool) Safe value extraction
Result[T] Transformation
Method Description
Map(func(T) T) Transform successful value
FlatMap(func(T) Result[T]) Transform with potential new errors
Validate(func(T) error) Validate with potential error
Result[T] Consumption
Method Description
Unwrap() T Get value or panic
UnwrapOr(default T) T Get value or default
Expect(msg string) T Get value or panic with message
Error Creation
Function Description
ErrOf(err error) Create from error
ErrOfFn(fn func() error) Create from error function
Errorf(format string, args ...any) Create formatted error
Error Handling
Method Description
Log() Log error with context
InspectErr(func(error)) Process error without consuming
Match(func(), func(error)) Pattern match on error presence

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func LogErr

func LogErr(err error, events ...func(e *zerolog.Event))

func LogErrCtx

func LogErrCtx(ctx context.Context, err error, events ...func(e *zerolog.Event))

func Must

func Must(err error, events ...func(e *zerolog.Event))

func Must1

func Must1[T any](ret T, err error) T

func Partition

func Partition[T any](results []Result[T]) ([]T, []error)

Partition separates a slice of Results into values and errors This function takes a slice of Results and separates them into two slices: one containing all successful values and another containing all errors. This is useful when you want to process all successes and handle all errors separately rather than stopping at the first error.

Example:

results := []result.Result[int]{result.OK(1), result.Fail[int](err1), result.OK(2)}
values, errors := result.Partition(results)
fmt.Printf("Values: %v, Errors: %v\n", values, errors)

func Recovery

func Recovery(setter ErrSetter, callbacks ...func(err error) error)

func RecoveryErr

func RecoveryErr(setter *error, callbacks ...func(err error) error)

func Throw

func Throw(setter ErrSetter, err error, contexts ...context.Context) bool

func ThrowErr

func ThrowErr(rawSetter *error, err error, contexts ...context.Context) bool

Types

type Checkable

type Checkable interface {
	IsOK() bool
	IsErr() bool
	GetErr() error
	String() string
}

Checkable defines types that can be checked for Ok/Error state

type ErrSetter

type ErrSetter interface {
	Checkable
	// contains filtered or unexported methods
}

type Error

type Error struct {
	// contains filtered or unexported fields
}

func ErrOf

func ErrOf(err error) Error

func ErrOfFn

func ErrOfFn(fn func() error) Error

func Errorf

func Errorf(msg string, args ...any) Error

func Run

func Run(executors ...func() error) Error

func (Error) Err

func (e Error) Err() error

func (Error) Expect

func (e Error) Expect(format string, args ...any)

func (Error) GetErr

func (e Error) GetErr() error

func (Error) IfErr

func (e Error) IfErr(fn func(error)) Error

func (Error) InspectErr

func (e Error) InspectErr(fn func(error))

func (Error) IsErr

func (e Error) IsErr() bool

func (Error) IsOK

func (e Error) IsOK() bool

func (Error) Log

func (e Error) Log(events ...func(e *zerolog.Event)) Error

func (Error) LogCtx

func (e Error) LogCtx(ctx context.Context, events ...func(e *zerolog.Event)) Error

func (Error) MapErr

func (e Error) MapErr(fn func(err error) error) Error

func (Error) MarshalJSON

func (e Error) MarshalJSON() ([]byte, error)

func (Error) Match

func (e Error) Match(onOk func(), onErr func(error))

Match allows pattern matching on the Error, applying the appropriate function This method provides a way to handle both success (no error) and error cases in a single operation, similar to pattern matching in functional languages.

Example:

errorResult.Match(
    func() { fmt.Println("No error occurred") },
    func(err error) { fmt.Printf("Error: %v\n", err) },
)

func (Error) MatchWithError

func (e Error) MatchWithError(onOk func() error, onErr func(error) error) error

MatchWithError allows pattern matching with an error-returning function This method is similar to Match, but both handler functions return an error, allowing for chaining operations that may themselves produce errors.

Example:

err := errorResult.MatchWithError(
    func() error { return nil },
    func(prevErr error) error { return fmt.Errorf("wrapped: %w", prevErr) },
)

func (Error) Must

func (e Error) Must()

func (Error) MustWithLog

func (e Error) MustWithLog(events ...func(e *zerolog.Event))

func (Error) String

func (e Error) String() string

func (Error) ThrowErr

func (e Error) ThrowErr(setter ErrSetter, contexts ...context.Context) bool

func (Error) TryUnwrap

func (e Error) TryUnwrap() (error, bool)

TryUnwrap attempts to unwrap the error, returning it and a boolean indicating if it's an error This method is useful when you want to safely extract an error from an Error result without triggering a panic. It returns the error (or nil if no error) and a boolean indicating whether an error was present.

Example:

if err, ok := errorResult.TryUnwrap(); ok {
    fmt.Printf("Error occurred: %v\n", err)
} else {
    fmt.Println("No error present")
}

func (Error) WithErr

func (e Error) WithErr(err error, tags ...errors.Tags) Error

func (Error) WithErrorf

func (e Error) WithErrorf(format string, args ...any) Error

func (Error) WithFn

func (e Error) WithFn(fn func() error) Error

type Future

type Future[T any] struct {
	// contains filtered or unexported fields
}

func Async

func Async[T any](fn func() Result[T]) *Future[T]

func (*Future[T]) Await

func (f *Future[T]) Await(ctxL ...context.Context) Result[T]

type FutureErr

type FutureErr struct {
	// contains filtered or unexported fields
}

func AsyncErr

func AsyncErr(fn func() Error) *FutureErr

func (*FutureErr) Await

func (f *FutureErr) Await(ctxL ...context.Context) Error

type ProxyErr

type ProxyErr struct {
	// contains filtered or unexported fields
}

func ErrProxyOf

func ErrProxyOf(err *error) ProxyErr

func (ProxyErr) GetErr

func (e ProxyErr) GetErr() error

func (ProxyErr) IsErr

func (e ProxyErr) IsErr() bool

func (ProxyErr) IsOK

func (e ProxyErr) IsOK() bool

func (ProxyErr) String

func (e ProxyErr) String() string

type Result

type Result[T any] struct {
	// contains filtered or unexported fields
}

func All

func All[T any](results ...Result[T]) Result[[]T]

func Collect

func Collect[T any](results []Result[T]) Result[[]T]

Collect takes a slice of Results and returns either all values or the first error This function processes a slice of Results and collects all successful values into a single Result containing a slice of values. If any Result contains an error, the function stops and returns that error in a Result.

Example:

results := []result.Result[int]{result.OK(1), result.OK(2), result.OK(3)}
collected := result.Collect(results)
if vals, ok := collected.TryUnwrap(); ok {
    fmt.Printf("Collected values: %v\n", vals)
}

func Fail

func Fail[T any](err error) Result[T]

func FlatMapTo

func FlatMapTo[T, U any](r Result[T], fn func(T) Result[U]) Result[U]

func MapTo

func MapTo[T, U any](r Result[T], fn func(T) U) Result[U]

func OK

func OK[T any](v T) Result[T]

func Try

func Try[T any](fn func() T) (r Result[T])

Try converts a function that may panic into a Result This function wraps a potentially panicking function and converts panics into error Results, providing a safer way to call functions that might panic.

Example:

result := result.Try(func() int {
    // Some operation that might panic
    return riskyOperation()
})
if value, ok := result.TryUnwrap(); ok {
    fmt.Printf("Success: %d\n", value)
}

func Wrap

func Wrap[T any](v T, err error) Result[T]

func WrapFn

func WrapFn[T any](fn func() (T, error)) Result[T]

func (Result[T]) CallIfOK

func (r Result[T]) CallIfOK(fn func(val T) error) Result[T]

func (Result[T]) Err

func (r Result[T]) Err() error

func (Result[T]) Expect

func (r Result[T]) Expect(format string, args ...any) T

func (Result[T]) FlatMap

func (r Result[T]) FlatMap(fn func(val T) Result[T]) Result[T]

func (Result[T]) GetErr

func (r Result[T]) GetErr() error

func (Result[T]) IfErr

func (r Result[T]) IfErr(fn func(err error)) Result[T]

IfErr executes fn if the result is an error, then returns the result unchanged. This is similar to InspectErr but allows chaining with other operations.

func (Result[T]) IfOK

func (r Result[T]) IfOK(fn func(val T)) Result[T]

IfOK executes fn if the result is OK, then returns the result unchanged. This is similar to Inspect but allows chaining with other operations.

func (Result[T]) Inspect

func (r Result[T]) Inspect(fn func(val T))

func (Result[T]) InspectErr

func (r Result[T]) InspectErr(fn func(err error))

func (Result[T]) IsErr

func (r Result[T]) IsErr() bool

func (Result[T]) IsOK

func (r Result[T]) IsOK() bool

func (Result[T]) Log

func (r Result[T]) Log(events ...func(e *zerolog.Event)) Result[T]

func (Result[T]) LogCtx

func (r Result[T]) LogCtx(ctx context.Context, events ...func(e *zerolog.Event)) Result[T]

func (Result[T]) Map

func (r Result[T]) Map(fn func(val T) T) Result[T]

func (Result[T]) MapErr

func (r Result[T]) MapErr(fn func(err error) error) Result[T]

func (Result[T]) MapErrOr

func (r Result[T]) MapErrOr(fn func(err error) Result[T]) Result[T]

func (Result[T]) MarshalJSON

func (r Result[T]) MarshalJSON() ([]byte, error)

func (Result[T]) Match

func (r Result[T]) Match(onOk func(T), onErr func(error))

Match allows pattern matching on the Result, applying the appropriate function This method provides a way to handle both success and error cases in a single operation similar to pattern matching in functional languages.

Example:

result.OK(42).Match(
    func(value int) { fmt.Printf("Success: %d\n", value) },
    func(err error) { fmt.Printf("Error: %v\n", err) },
)

func (Result[T]) MatchWithResult

func (r Result[T]) MatchWithResult(onOk func(T) Result[T], onErr func(error) Result[T]) Result[T]

MatchWithResult allows pattern matching with a result-returning function This method is similar to Match, but both handler functions return a Result[T], allowing for chaining operations that may themselves produce Results.

Example:

result.OK(42).MatchWithResult(
    func(value int) result.Result[int] { return result.OK(value * 2) },
    func(err error) result.Result[int] { return result.Fail[int](err) },
)

func (Result[T]) Must

func (r Result[T]) Must(events ...func(e *zerolog.Event))

func (Result[T]) Or

func (r Result[T]) Or(defaultVal T) Result[T]

func (Result[T]) OrElse

func (r Result[T]) OrElse(fn func() T) Result[T]

func (Result[T]) String

func (r Result[T]) String() string

func (Result[T]) ThrowErr

func (r Result[T]) ThrowErr(setter ErrSetter, contexts ...context.Context) bool

func (Result[T]) TryUnwrap

func (r Result[T]) TryUnwrap() (T, bool)

TryUnwrap attempts to unwrap the value, returning it and a boolean indicating success This method is useful when you want to safely extract a value from a Result without triggering a panic. It returns the value (or zero value if error) and a boolean indicating whether the extraction was successful.

Example:

if value, ok := result.TryUnwrap(); ok {
    fmt.Printf("Success: %v\n", value)
} else {
    fmt.Println("Operation failed")
}

func (Result[T]) Unwrap

func (r Result[T]) Unwrap() T

func (Result[T]) UnwrapErr

func (r Result[T]) UnwrapErr() (T, error)

func (Result[T]) UnwrapOr

func (r Result[T]) UnwrapOr(defaultVal T) T

func (Result[T]) UnwrapOrElse

func (r Result[T]) UnwrapOrElse(fn func() T) T

func (Result[T]) UnwrapOrEmpty

func (r Result[T]) UnwrapOrEmpty() (t T)

func (Result[T]) UnwrapOrLog

func (r Result[T]) UnwrapOrLog(events ...func(e *zerolog.Event)) T

func (Result[T]) UnwrapOrThrow

func (r Result[T]) UnwrapOrThrow(setter ErrSetter, contexts ...context.Context) (t T)

func (Result[T]) Validate

func (r Result[T]) Validate(fn func(val T) error) Result[T]

func (Result[T]) ValueTo

func (r Result[T]) ValueTo(v *T) Error

func (Result[T]) WithErr

func (r Result[T]) WithErr(err error, tags ...errors.Tags) Result[T]

func (Result[T]) WithErrorf

func (r Result[T]) WithErrorf(format string, args ...any) Result[T]

func (Result[T]) WithFn

func (r Result[T]) WithFn(fn func() (T, error)) Result[T]

func (Result[T]) WithValue

func (r Result[T]) WithValue(v T) Result[T]

type Void

type Void = funk.Void

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL