Documentation
¶
Overview ¶
Package gofp provides Rust-inspired functional primitives for Go.
gofp brings type-safe error handling and optional values to Go through three core types: Result, Option, and [Either]. All types are designed for zero heap allocation, full type safety, and composable pipelines.
Core Types ¶
Result[T] represents a computation that either succeeds with a value of type T, or fails with an error:
r := gofp.Of(strconv.Atoi("42")) // Result[int]
r.IfOk(func(n int) { fmt.Println(n) }).
IfErr(func(err error) { fmt.Println(err) })
Option[T] represents a value that may or may not exist, replacing nil pointer patterns with an explicit type:
o := gofp.FromPtr(ptr) // Option[T]
o.IfSome(func(v T) { ... }).
IfNone(func() { ... })
Either[L, R] represents a value that is one of two possible types. Unlike Result, neither side implies failure both are valid domain values. See the either sub-package for constructors and operations.
Error Handling ¶
gofp provides two approaches for propagating errors through a call chain.
FlatMap composes functions that return Result, short-circuiting on the first error:
gofp.FlatMap(
gofp.FlatMap(parse(s), validate),
process,
)
Try runs a function and recovers from Result panics, similar to Rust's ? operator. Only panics originating from Result.Unwrap are caught — real bugs are re-panicked:
result := gofp.Try(func() string {
age := parse(s).Unwrap() // Err → caught
age = validate(age).Unwrap() // Err → caught
return format(age).Unwrap() // Err → caught
})
Sub-packages ¶
Transformations that change the type parameter (T → U) cannot be expressed as methods in Go. These are provided as free functions in dedicated sub-packages:
- github.com/Alsond5/gofp/result — Map, FlatMap, AllOf, Partition, FirstOk and more
- github.com/Alsond5/gofp/option — Map, FlatMap, Zip, Match and more
- github.com/Alsond5/gofp/either — Either[L,R], Fold, Partition and more
- github.com/Alsond5/gofp/must — Panic helpers for program initialization
Performance ¶
Result[T] and Option[T] are plain structs no interfaces, no heap allocation. Value receivers ensure values stay on the stack. The ok and some boolean fields solve Go's zero value ambiguity without runtime overhead, as all accessor methods are inlined by the compiler.
Design Decisions ¶
Methods are limited to transformations that preserve the type parameter (T → T). Transformations that change the type (T → U) are free functions in sub-packages, as Go does not allow methods to introduce new type parameters.
Index ¶
- func TryCatch[L, R any](try func() L, catch func(error) R) (e either.Either[L, R])
- type Option
- func (o Option[T]) Expect(msg string) T
- func (o Option[T]) Filter(f func(T) bool) Option[T]
- func (o Option[T]) IfNone(f func()) Option[T]
- func (o Option[T]) IfSome(f func(T)) Option[T]
- func (o Option[T]) Inspect(f func(T)) Option[T]
- func (o Option[T]) IsNone() bool
- func (o Option[T]) IsNoneOr(f func(T) bool) bool
- func (o Option[T]) IsSome() bool
- func (o Option[T]) IsSomeAnd(f func(T) bool) bool
- func (o Option[T]) Match(someFn func(T), noneFn func())
- func (o Option[T]) OkOr(err error) Result[T]
- func (o Option[T]) OkOrElse(errFn func() error) Result[T]
- func (o Option[T]) Or(other Option[T]) Option[T]
- func (o Option[T]) OrElse(f func() Option[T]) Option[T]
- func (o Option[T]) ToPtr() *T
- func (o Option[T]) Unwrap() T
- func (o Option[T]) UnwrapOr(defaultValue T) T
- func (o Option[T]) UnwrapOrElse(f func() T) T
- func (o Option[T]) UnwrapOrZero() T
- func (o Option[T]) Xor(other Option[T]) Option[T]
- type Result
- func Do(err error) Result[Unit]
- func Err[T any](err error) Result[T]
- func Of[T any](value T, err error) Result[T]
- func Of2[A, B any](a A, b B, err error) Result[tuple.Pair[A, B]]
- func Of3[A, B, C any](a A, b B, c C, err error) Result[tuple.Triple[A, B, C]]
- func Ok[T any](value T) Result[T]
- func Transpose[T any](o Option[Result[T]]) Result[Option[T]]
- func Try[T any](f func() T) (r Result[T])
- func (r Result[T]) ContainsErr(target error) bool
- func (r Result[T]) Err() Option[error]
- func (r Result[T]) Expect(msg string) T
- func (r Result[T]) ExpectErr(msg string) error
- func (r Result[T]) IfErr(f func(error)) Result[T]
- func (r Result[T]) IfOk(f func(T)) Result[T]
- func (r Result[T]) IntoErr() error
- func (r Result[T]) IntoOk() T
- func (r Result[T]) IsErr() bool
- func (r Result[T]) IsErrAnd(f func(error) bool) bool
- func (r Result[T]) IsOk() bool
- func (r Result[T]) IsOkAnd(f func(T) bool) bool
- func (r Result[T]) MapErr(f func(error) error) Result[T]
- func (r Result[T]) Ok() Option[T]
- func (r Result[T]) Or(alternative Result[T]) Result[T]
- func (r Result[T]) OrElse(f func(error) Result[T]) Result[T]
- func (r Result[T]) Tap(okFn func(T), errFn func(error)) Result[T]
- func (r Result[T]) Unpack() (T, error)
- func (r Result[T]) Unwrap() T
- func (r Result[T]) UnwrapErr() error
- func (r Result[T]) UnwrapOr(defaultValue T) T
- func (r Result[T]) UnwrapOrElse(f func(error) T) T
- func (r Result[T]) UnwrapOrZero() T
- type ResultError
- type Unit
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func TryCatch ¶
TryCatch runs try and recovers from Result panics. On success, returns Left(try()). On gofp panic, calls catch and returns Right(catch(err)). Real panics are re-panicked — not swallowed.
either.TryCatch(
func() int { return parse(s).Unwrap() },
func(err error) string { return err.Error() },
)
Types ¶
type Option ¶
type Option[T any] struct { // contains filtered or unexported fields }
Option[T] represents either a value of type T (Some) or no value (None).
Zero value is NOT valid. Always use Some(), None(), or constructor functions.
Option is immutable by design: all transformation methods return a new Option.
func FromPtr ¶
FromPtr converts a pointer to an Option. If ptr is nil, returns None. Otherwise returns Some(*ptr). This is the primary bridge from legacy *T code to Option[T].
var p *User = db.FindUser(id) o := gofp.FromPtr(p) // Option[User]
func FromZero ¶
func FromZero[T comparable](value T) Option[T]
FromZero returns None if value equals the zero value of T, otherwise returns Some(value).
Useful for converting bare int/string/etc returns where zero means "absent". Use with caution: zero is a valid value in many domains.
gofp.FromZero(0) // None[int]
gofp.FromZero(42) // Some(42)
gofp.FromZero("") // None[string]
func (Option[T]) Expect ¶
Expect returns the contained value. Panics with msg if the Option is None. Prefer over Unwrap when you want a meaningful panic message.
user := o.Expect("user must exist after authentication")
func (Option[T]) Filter ¶
Filter returns the Option unchanged if Some and f(value) is true. Returns None if the Option is None or f(value) is false.
even := gofp.Some(4).Filter(func(n int) bool { return n%2 == 0 }) // Some(4)
odd := gofp.Some(3).Filter(func(n int) bool { return n%2 == 0 }) // None
func (Option[T]) IfNone ¶
IfNone calls f if the Option is None. Returns the original Option unchanged for chaining.
o.IfNone(func() { log.Println("not found") })
func (Option[T]) IfSome ¶
IfSome calls f with the contained value if Some. Returns the original Option unchanged for chaining.
o.IfSome(func(u User) { log.Println("found:", u.Name) })
func (Option[T]) Inspect ¶
Inspect calls f with the contained value if Some, then returns the Option unchanged. Useful for debugging in a chain without breaking it.
o.Inspect(func(v int) { log.Println("got:", v) }).UnwrapOr(0)
func (Option[T]) IsNone ¶
IsNone reports whether the Option contains no value.
if o.IsNone() { ... }
func (Option[T]) IsNoneOr ¶
IsNoneOr returns true if the Option is None, or if it contains a value and f(value) returns true.
gofp.None[int]().IsNoneOr(func(n int) bool { return n > 0 }) // true
gofp.Some(42).IsNoneOr(func(n int) bool { return n > 0 }) // true
gofp.Some(-1).IsNoneOr(func(n int) bool { return n > 0 }) // false
func (Option[T]) IsSomeAnd ¶
IsSomeAnd returns true if the Option contains a value and f(value) returns true. Returns false for None without calling f.
gofp.Some(42).IsSomeAnd(func(n int) bool { return n > 0 }) // true
gofp.None[int]().IsSomeAnd(func(n int) bool { return true }) // false
func (Option[T]) Match ¶
func (o Option[T]) Match(someFn func(T), noneFn func())
Match calls someFn with the value if Some, or noneFn if None. Neither function returns a value, use this for side effects only.
If you need to return a value from each branch, use the free function `gofp.Match` instead.
name := o.Match(
func(u User) { fmt.Println(u.Name) },
func() string { fmt.Println("anonymous") },
)
func (Option[T]) OkOr ¶
OkOr converts Option[T] to Result[T]. Some(v) becomes Ok(v), None becomes Err(err).
r := gofp.Some(42).OkOr(errors.New("not found"))
func (Option[T]) OkOrElse ¶
OkOrElse converts Option[T] to a Result[T] tuple. Some(v) returns Ok(v), None calls errFn and returns Err(errFn()). Prefer over OkOr when the error is expensive to construct.
r := o.OkOrElse(func() error { return fmt.Errorf("user %d not found", id) })
func (Option[T]) Or ¶
Or returns the Option if it is Some, otherwise returns other.
gofp.Some(1).Or(gofp.Some(2)) // Some(1) gofp.None[int]().Or(gofp.Some(2)) // Some(2)
func (Option[T]) OrElse ¶
OrElse returns the Option if it is Some, otherwise calls f and returns its result. Prefer over Or when the fallback is expensive to compute.
o.OrElse(func() gofp.Option[User] { return getFromCache(id) })
func (Option[T]) ToPtr ¶
func (o Option[T]) ToPtr() *T
ToPtr converts the Option to a *T pointer. Returns nil for None, a pointer to the contained value for Some.
Note: the returned pointer points to a copy of the value, not the original.
ptr := option.Some(42).ToPtr() // *int pointing to 42 ptr := option.None[int]().ToPtr() // nil
func (Option[T]) Unwrap ¶
func (o Option[T]) Unwrap() T
Unwrap returns the contained value. Panics if the Option is None.
Use when you are certain the Option is Some, or in tests.
func (Option[T]) UnwrapOr ¶
func (o Option[T]) UnwrapOr(defaultValue T) T
UnwrapOr returns the contained value if Some, or defaultValue if None.
name := o.UnwrapOr("anonymous")
func (Option[T]) UnwrapOrElse ¶
func (o Option[T]) UnwrapOrElse(f func() T) T
UnwrapOrElse returns the contained value if Some, or calls f and returns its result if None. Prefer over UnwrapOr when the default is expensive to compute.
name := o.UnwrapOrElse(func() string { return generateDefaultName() })
func (Option[T]) UnwrapOrZero ¶
func (o Option[T]) UnwrapOrZero() T
UnwrapOrZero returns the contained value if Some, or the zero value of T if None.
count := o.UnwrapOrZero() // 0 if None
func (Option[T]) Xor ¶
Xor returns Some if exactly one of o, other is Some. Returns None otherwise.
gofp.Some(1).Xor(gofp.None[int]()) // Some(1) gofp.None[int]().Xor(gofp.Some(2)) // Some(2) gofp.Some(1).Xor(gofp.Some(2)) // None — both are Some gofp.None[int]().Xor(gofp.None[int]()) // None — neither is Some
type Result ¶
type Result[T any] struct { // contains filtered or unexported fields }
Result represents either a successful value of type T (Ok) or a failure with an error (Err).
Zero value is NOT valid, always use Ok(), Err(), or Of() constructors.
Result is immutable by design: all transformation methods return a new Result rather than modifying the receiver.
func Do ¶
Do wraps a single error return into Result[Unit]. Use for functions that return only error with no value.
gofp.Do(os.Remove("file.txt")).IfErr(func(err error) { log.Println(err) })
func Err ¶
Err returns a failed Result containing err. If err is nil, Ok(zero value) is returned. This matches Go's convention where nil error means success.
r := result.Err[int](errors.New("not found"))
func Of ¶
Of wraps a (T, error) tuple the standard Go return signature into a Result[T]. This is the primary bridge between stdlib and gostd.
result.Of(strconv.Atoi("42"))
result.Of(os.Open("file.txt"))
result.Of(json.Marshal(data))
func Try ¶
Try runs f and recovers from Result panics caused by Unwrap. If f panics with a gofp error, returns Err with that error. Real panics (nil pointer, index out of range) are re-panicked.
gofp.Try(func() string {
age := parse(s).Unwrap()
return format(age).Unwrap()
})
func (Result[T]) ContainsErr ¶
ContainsErr returns true if the Result is Err and the error matches target using errors.Is semantics.
r.ContainsErr(ErrNotFound)
func (Result[T]) Err ¶
Err converts Result[T] to Option[error]. Err(e) becomes Some(e), Ok becomes None.
r.Err().IfSome(func(err error) { log.Println(err) })
func (Result[T]) Expect ¶
Expect returns the contained value if Ok. Panics with the provided message (plus the error) if Err. Prefer over Unwrap when you want a meaningful panic message.
val := r.Expect("config must be loaded at startup")
func (Result[T]) ExpectErr ¶
ExpectErr returns the contained error. Panics with msg if the Result is Ok.
err := r.ExpectErr("expected failure")
func (Result[T]) IfErr ¶
IfErr calls f with the contained error if Err. Returns the original Result unchanged for chaining.
r.IfErr(func(err error) { log.Println(err) })
func (Result[T]) IfOk ¶
IfOk calls f with the contained value if Ok. Returns the original Result unchanged for chaining.
r.IfOk(func(n int) { fmt.Println(n) })
func (Result[T]) IntoErr ¶
IntoErr returns the raw error without any check. Returns nil if the Result is Ok. Use only when you are certain the Result is Err.
func (Result[T]) IntoOk ¶
func (r Result[T]) IntoOk() T
IntoOk returns the raw value without any check. Returns zero value if the Result is Err. Use only when you are certain the Result is Ok.
func (Result[T]) IsErrAnd ¶
IsErrAnd returns true if the Result is Err and f(err) returns true.
r.IsErrAnd(func(err error) bool { return errors.Is(err, ErrNotFound) })
func (Result[T]) IsOk ¶
IsOk reports whether the Result contains a successful value.
if r.IsOk() { ... }
func (Result[T]) IsOkAnd ¶
IsOkAnd returns true if the Result is Ok and f(value) returns true.
r.IsOkAnd(func(n int) bool { return n > 0 })
func (Result[T]) MapErr ¶
MapErr applies f to the error if Err, returning a new Result with the mapped error. Returns the Result unchanged if Ok.
r.MapErr(func(err error) error { return fmt.Errorf("wrapped: %w", err) })
func (Result[T]) Ok ¶
Ok converts Result[T] to Option[T]. Ok(v) becomes Some(v), Err becomes None.
gofp.Of(strconv.Atoi(s)).Ok() // Option[int]
func (Result[T]) OrElse ¶
OrElse calls f with the error if Err, returning f's result. Returns the Result unchanged if Ok.
r.OrElse(func(err error) Result[int] { return gofp.Ok(0) })
func (Result[T]) Tap ¶
Tap calls okFn if Ok or errFn if Err, then returns the Result unchanged. Either function may be nil.
r.Tap(
func(v int) { log.Println("ok:", v) },
func(err error) { log.Println("err:", err) },
)
func (Result[T]) Unpack ¶
Unpack returns the (value, error) tuple. Use this to convert back to idiomatic Go returns.
value, err := r.Unpack()
func (Result[T]) Unwrap ¶
func (r Result[T]) Unwrap() T
Unwrap returns the contained value. Panics with the error message if the Result is an Err.
Use when you are certain the Result is Ok, or in tests.
val := r.Unwrap()
func (Result[T]) UnwrapOr ¶
func (r Result[T]) UnwrapOr(defaultValue T) T
UnwrapOr returns the contained value if Ok, or the provided default value if Err.
name := r.UnwrapOr("anonymous")
func (Result[T]) UnwrapOrElse ¶
UnwrapOrElse returns the contained value if Ok, or calls f with the error and returns its result if Err. Prefer over UnwrapOr when the default is expensive to compute.
name := r.UnwrapOrElse(func(err error) string {
log.Println(err)
return "anonymous"
})
func (Result[T]) UnwrapOrZero ¶
func (r Result[T]) UnwrapOrZero() T
UnwrapOrZero returns the contained value if Ok, or the zero value of T if Err.
count := r.UnwrapOrZero() // 0 if Err
type ResultError ¶
type ResultError string
ResultError is a string-based error type for sentinel errors within gofp. Defined as a named type to avoid allocation from errors.New.
const ErrNoResults ResultError = "result: no results provided"
ErrNoResults is returned by FirstOk when no results are provided.
func (ResultError) Error ¶
func (e ResultError) Error() string
Error implements the error interface.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package either provides the Either[L, R] type for Go.
|
Package either provides the Either[L, R] type for Go. |
|
Package must provides panic-or-value helpers for Go.
|
Package must provides panic-or-value helpers for Go. |
|
Package option provides free functions for transforming and combining Option[T] values from the gofp package.
|
Package option provides free functions for transforming and combining Option[T] values from the gofp package. |
|
Package result provides free functions for transforming and combining Result[T] values from the gofp package.
|
Package result provides free functions for transforming and combining Result[T] values from the gofp package. |
|
Package tuple provides generic Pair and Triple types for holding two or three values of potentially different types.
|
Package tuple provides generic Pair and Triple types for holding two or three values of potentially different types. |