result

package
v2.0.0-beta.13 Latest Latest
Warning

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

Go to latest
Published: Jan 13, 2026 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 Event))

func LogErrCtx

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

func Must

func Must(err error, events ...func(e 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 WrapErr

func WrapErr[T any](v T, err error) (t T, gErr 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 Event)) Error

func (Error) LogCtx

func (e Error) LogCtx(ctx context.Context, events ...func(e 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 Event))

func (Error) String

func (e Error) String() string

func (Error) Throw

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

func (Error) ThrowErr

func (e Error) ThrowErr(err *error, 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) Unwrap

func (e Error) Unwrap() (void Void)

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 Event

type Event struct {
	*log.Event
}

func (Event) Msg

func (e Event) Msg(msg string)

func (Event) MsgFunc

func (e Event) MsgFunc(createMsg func() string)

func (Event) Msgf

func (e Event) Msgf(format string, v ...any)

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 ProxyOf

func ProxyOf(err *error) ProxyErr

func (ProxyErr) Err

func (e ProxyErr) Err() error

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 MapTo

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

func MapValTo

func MapValTo[T, U any](r Result[T], fn func(T) Result[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]

CallIfOK calls the provided function with the value if the result is OK,

func (Result[T]) Err

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

Err returns the error if the result is an error, or nil if it's OK.

func (Result[T]) Expect

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

Expect panics if the result is an error.

func (Result[T]) GetErr

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

GetErr returns the error if the result is an error, or nil if it's OK.

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))

Inspect executes fn if the result is OK, then returns the result unchanged.

func (Result[T]) InspectErr

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

InspectErr executes fn if the result is an error.

func (Result[T]) IsErr

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

IsErr returns true if the result is an error.

func (Result[T]) IsOK

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

IsOK returns true if the result is OK.

func (Result[T]) Log

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

Log logs the error.

func (Result[T]) LogCtx

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

LogCtx logs the error with the provided context.

func (Result[T]) Map

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

Map calls fn with the value if the result is OK, then returns the result unchanged.

func (Result[T]) MapErr

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

MapErr calls fn with the error if the result is an error, then returns the result unchanged.

func (Result[T]) MapErrOr

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

MapErrOr calls fn with the error if the result is an error, then returns the result unchanged.

func (Result[T]) MapVal

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

MapVal calls fn with the value if the result is OK, then returns the result unchanged.

func (Result[T]) MarshalJSON

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

MarshalJSON returns a JSON representation of the result.

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 Event))

Must panics if the result is an error.

func (Result[T]) Or

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

Or returns a new Result with the provided default value if the current Result is an error.

func (Result[T]) OrElse

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

OrElse returns a new Result with the provided default value if the current Result is an error.

func (Result[T]) String

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

String returns a string representation of the result.

func (Result[T]) Throw

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

Throw returns the value if it's OK, or throws an error if it's an error.

func (Result[T]) ThrowErr

func (r Result[T]) ThrowErr(err *error, contexts ...context.Context) bool

ThrowErr throws an error if the result is an error.

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

Unwrap returns the value if it's OK, or panics if it's an error.

func (Result[T]) UnwrapErr

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

UnwrapErr returns the value and error if it's OK, or the zero value and nil error if it's an error.

func (Result[T]) UnwrapOr

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

UnwrapOr returns the value if it's OK, or the default value if it's an error.

func (Result[T]) UnwrapOrElse

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

UnwrapOrElse returns the value if it's OK, or the result of the provided function if it's an error.

func (Result[T]) UnwrapOrEmpty

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

UnwrapOrEmpty returns the value if it's OK, or the zero value if it's an error.

func (Result[T]) UnwrapOrLog

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

UnwrapOrLog attempts to unwrap the value, returning it and panicking if an error occurs.

func (Result[T]) UnwrapOrThrow

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

UnwrapOrThrow returns the value if it's OK, or throws an error if it's an error.

func (Result[T]) Validate

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

Validate calls fn with the value if the result is OK, then returns the result unchanged.

func (Result[T]) ValueTo

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

ValueTo extracts the value from the Result and assigns it to the provided variable.

func (Result[T]) WithErr

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

WithErr returns a new Result with the provided error.

func (Result[T]) WithErrorf

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

WithErrorf returns a new Result with the provided error message.

func (Result[T]) WithFn

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

WrapFn wraps a function into a Result.

func (Result[T]) WithValue

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

WithValue wraps a value into a Result.

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