Documentation
¶
Overview ¶
Package mu provides functional programming primitives for Go, including Option, Result, and Either types for safe and expressive error handling and data manipulation.
The package offers three main abstractions:
- Option: Represents optional values, avoiding nil pointer issues
- Either: Represents a disjoint union of two possible value types
- Result: Represents operations that may succeed or fail with an error
Each type comes with a rich set of methods for functional composition, transformation, and safe value extraction. The types implement standard Go interfaces for JSON marshaling, SQL scanning, and string representation.
Example usage:
// Option example opt := Some(42) doubled := opt.Map(func(x int) int { return x * 2 }) fmt.Println(doubled.OrZero()) // 84 // Result example result := Try(func() (int, error) { return strconv.Atoi("123") }) fmt.Println(result.OrZero()) // 123 // Either example either := Right[string, int](42) doubled := either.MapRight(func(x int) int { return x * 2 }) fmt.Println(doubled.RightOrPanic()) // 84
Design Patterns and Go Generics Limitations ¶
This library follows a specific design pattern to work around Go's generics limitations while providing both ergonomic and powerful APIs.
## Method vs Function Distinction
Due to Go's language specification, methods cannot have additional type parameters beyond those defined on the receiver type. This means we cannot write:
func (o Option[T]) Map[U any](f func(T) U) Option[U] // ❌ Not allowed
Instead, methods in this library are endomorphisms (same type in, same type out):
func (o Option[T]) Map(f func(T) T) Option[T] // ✅ Allowed
For type-changing transformations, we provide standalone functions:
func MapOptionTo[T, U any](o Option[T], f func(T) U) Option[U] // ✅ Allowed
## Usage Guidelines
Use methods when:
- Transforming a value while keeping the same type (e.g., `x * 2` for int)
- Chaining operations fluently: `opt.Map(f1).Filter(p).Map(f2)`
Use standalone functions when:
- Converting between different types (e.g., int to string)
- You need the additional type parameter flexibility
Example:
// Method: int → int transformation opt := Some(42) doubled := opt.Map(func(x int) int { return x * 2 }) // Function: int → string transformation opt := Some(42) str := MapOptionTo(opt, func(x int) string { return fmt.Sprintf("%d", x) })
For more details on this limitation, see: https://github.com/golang/go/issues/49085
Index ¶
- type Either
- func (e Either[L, R]) FlatMap(f func(R) Either[L, R]) Either[L, R]
- func (e Either[L, R]) FlatMapLeft(f func(L) Either[L, R]) Either[L, R]
- func (e Either[L, R]) Flatten() Either[L, R]
- func (e Either[L, R]) Fold(onLeft func(L) R, onRight func(R) R) R
- func (e Either[L, R]) IsLeft() bool
- func (e Either[L, R]) IsRight() bool
- func (e Either[L, R]) Left() Option[L]
- func (e Either[L, R]) LeftOrElse(fallback L) L
- func (e Either[L, R]) LeftOrElseF(fallback func() L) L
- func (e Either[L, R]) LeftOrPanic() L
- func (e Either[L, R]) LeftOrZero() L
- func (e Either[L, R]) Map(f func(R) R) Either[L, R]
- func (e Either[L, R]) MapLeft(f func(L) L) Either[L, R]
- func (e Either[L, R]) OrElse(fallback R) R
- func (e Either[L, R]) OrElseF(fallback func() R) R
- func (e Either[L, R]) OrPanic() R
- func (e Either[L, R]) OrZero() R
- func (e Either[L, R]) Right() Option[R]
- func (e Either[L, R]) Swap() Either[R, L]
- func (e Either[L, R]) Tap(f func(R)) Either[L, R]
- func (e Either[L, R]) TapLeft(f func(L)) Either[L, R]
- func (e Either[L, R]) Unwrap() (R, bool)
- func (e Either[L, R]) UnwrapLeft() (L, bool)
- type Option
- func (o Option[T]) Filter(f func(T) bool) Option[T]
- func (o Option[T]) FlatMap(f func(T) Option[T]) Option[T]
- func (o Option[T]) Flatten() Option[T]
- func (o Option[T]) Fold(onSome func(T) T, onNone func() T) T
- func (o Option[T]) IsNone() bool
- func (o Option[T]) IsSome() bool
- func (o Option[T]) Map(f func(T) T) Option[T]
- func (o Option[T]) OrElse(fallback T) T
- func (o Option[T]) OrElseF(fallback func() T) T
- func (o Option[T]) OrPanic() T
- func (o Option[T]) OrZero() T
- func (o Option[T]) Tap(f func(T)) Option[T]
- func (o Option[T]) ToResult(err error) Result[T]
- func (o Option[T]) Unwrap() (T, bool)
- type Result
- func (r Result[T]) ErrOrElse(fallback error) error
- func (r Result[T]) ErrOrElseF(fallback func() error) error
- func (r Result[T]) ErrOrPanic() error
- func (r Result[T]) ErrOrZero() error
- func (r Result[T]) Error() Option[error]
- func (r Result[T]) FlatMap(f func(T) Result[T]) Result[T]
- func (r Result[T]) FlatMapErr(f func(error) Result[T]) Result[T]
- func (r Result[T]) Flatten() Result[T]
- func (r Result[T]) Fold(onOk func(T) T, onErr func(error) T) T
- func (r Result[T]) IsErr() bool
- func (r Result[T]) IsOk() bool
- func (r Result[T]) Map(f func(T) T) Result[T]
- func (r Result[T]) MapErr(f func(error) error) Result[T]
- func (r Result[T]) OrElse(fallback T) T
- func (r Result[T]) OrElseF(fallback func() T) T
- func (r Result[T]) OrPanic() T
- func (r Result[T]) OrZero() T
- func (r Result[T]) Recover(f func(error) T) Result[T]
- func (r Result[T]) RecoverF(f func(error) Result[T]) Result[T]
- func (r Result[T]) Tap(f func(T)) Result[T]
- func (r Result[T]) TapErr(f func(error)) Result[T]
- func (r Result[T]) Unpack() (T, error)
- func (r Result[T]) Unwrap() (T, bool)
- func (r Result[T]) UnwrapErr() (error, bool)
- func (r Result[T]) Value() Option[T]
- type Unit
Examples ¶
- Either.FlatMap
- Either.FlatMapLeft
- Either.Flatten
- Either.Fold
- Either.IsLeft
- Either.IsRight
- Either.Left
- Either.LeftOrElse
- Either.LeftOrElseF
- Either.LeftOrPanic
- Either.LeftOrZero
- Either.Map
- Either.MapLeft
- Either.OrElse
- Either.OrElseF
- Either.OrPanic
- Either.OrZero
- Either.Right
- Either.Swap
- Either.Tap
- Either.TapLeft
- Either.Unwrap
- Either.UnwrapLeft
- Err
- Left
- None
- Ok
- Option.Filter
- Option.FlatMap
- Option.Flatten
- Option.Fold
- Option.IsNone
- Option.IsSome
- Option.Map
- Option.OrElse
- Option.OrElseF
- Option.OrPanic
- Option.OrZero
- Option.Tap
- Option.ToResult
- Option.Unwrap
- Result.ErrOrElse
- Result.ErrOrElseF
- Result.ErrOrPanic
- Result.ErrOrZero
- Result.Error
- Result.FlatMap
- Result.FlatMapErr
- Result.Flatten
- Result.Fold
- Result.IsErr
- Result.IsOk
- Result.Map
- Result.MapErr
- Result.OrElse
- Result.OrElseF
- Result.OrPanic
- Result.OrZero
- Result.Recover
- Result.RecoverF
- Result.Tap
- Result.TapErr
- Result.Unpack
- Result.Unpack (BridgeToLegacyCode)
- Result.Unpack (WithFunctions)
- Result.Unwrap
- Result.UnwrapErr
- Result.Value
- Right
- Some
- Try
- Try0
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Either ¶
Either represents a value of one of two possible types (a disjoint union). An instance of `Either[L, R]` is either a Left or a Right. This implementation is right-biased: methods such as `Map`, `FlatMap`, and `Get` operate on the Right side by default.
A right-biased approach offers several advantages:
- It follows the common convention where Right is the "happy-path" value and Left represents an alternative or error. This makes it natural to chain operations without repetitive branching.
- Method signatures stay concise because they focus on the Right type, improving readability.
- It allows Either to be treated as a monad, enabling fluent functional composition on the successful value.
Either is still a general-purpose sum type and remains distinct from Result, which is specialized for success/failure semantics.
func Left ¶
Left returns an `Either[L, R]` that contains a Left value.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { either := mu.Left[string, int]("error message") fmt.Println("Left(\"error message\"):", either.IsLeft()) fmt.Println("Left value:", either.LeftOrZero()) }
Output: Left("error message"): true Left value: error message
func Right ¶
Right returns an `Either[L, R]` that contains a Right value.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { either := mu.Right[string, int](42) fmt.Println("Right(42):", either.IsRight()) fmt.Println("Right value:", either.OrZero()) }
Output: Right(42): true Right value: 42
func (Either[L, R]) FlatMap ¶
FlatMap returns the original Left if the Either is a Left, otherwise calls the function with the Right value and returns the new Either. For type-changing operations (R→R2), use pkg/github.com/appthrust/mu/mue.FlatMapTo instead. See package docs for details.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // FlatMap with Right value right := mu.Right[string, int](42) result := right.FlatMap(func(x int) mu.Either[string, int] { if x > 40 { return mu.Right[string, int](x * 2) } return mu.Left[string, int]("too small") }) fmt.Println("Right(42).FlatMap(x*2 if >40):", result.OrZero()) // FlatMap with Left value left := mu.Left[string, int]("error") result2 := left.FlatMap(func(x int) mu.Either[string, int] { return mu.Right[string, int](x * 2) }) fmt.Println("Left(\"error\").FlatMap():", result2.LeftOrZero()) }
Output: Right(42).FlatMap(x*2 if >40): 84 Left("error").FlatMap(): error
func (Either[L, R]) FlatMapLeft ¶
FlatMapLeft returns the original Right if the Either is a Right, otherwise calls the function with the Left value and returns the new Either. For type-changing operations (L→L2), use pkg/github.com/appthrust/mu/mue.FlatMapLeftTo instead. See package docs for details.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // FlatMapLeft with Left value left := mu.Left[string, int]("error") result := left.FlatMapLeft(func(s string) mu.Either[string, int] { return mu.Left[string, int]("processed: " + s) }) fmt.Println("Left(\"error\").FlatMapLeft():", result.LeftOrZero()) // FlatMapLeft with Right value right := mu.Right[string, int](42) result2 := right.FlatMapLeft(func(s string) mu.Either[string, int] { return mu.Left[string, int]("processed: " + s) }) fmt.Println("Right(42).FlatMapLeft():", result2.OrZero()) }
Output: Left("error").FlatMapLeft(): processed: error Right(42).FlatMapLeft(): 42
func (Either[L, R]) Flatten ¶
Flatten converts an right-biased `Either[L, Either[L, R]]` into an `Either[L, R]`. This requires the inner type R to be an `Either[L, R]`.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // Note: Flatten works on properly nested Either types through type assertion // Create nested Either scenario innerRight := mu.Right[string, int](42) outerRight := mu.Right[string, mu.Either[string, int]](innerRight) result := outerRight.Flatten() fmt.Println("Nested Right contains value:", result.IsRight()) fmt.Println("Value:", result.OrZero()) // Example with inner Left innerLeft := mu.Left[string, int]("inner error") outerWithLeft := mu.Right[string, mu.Either[string, int]](innerLeft) result2 := outerWithLeft.Flatten() fmt.Println("Nested with inner Left:", result2.IsLeft()) fmt.Printf("Left value:%s\n", result2.LeftOrZero()) // Example with outer Left outerLeft := mu.Left[string, mu.Either[string, int]]("outer error") result3 := outerLeft.Flatten() fmt.Println("Outer Left flattened:", result3.IsLeft()) fmt.Println("Left value:", result3.LeftOrZero()) }
Output: Nested Right contains value: true Value: { 42 false} Nested with inner Left: false Left value: Outer Left flattened: true Left value: outer error
func (Either[L, R]) Fold ¶
func (e Either[L, R]) Fold(onLeft func(L) R, onRight func(R) R) R
Fold applies the function f to the contained value of `Either[L, R]`, returning the result of onLeft or onRight depending on the variant. For type-changing transformations (L→U, R→U), use pkg/github.com/appthrust/mu/mue.Fold instead. See package docs for details.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // Fold with Left value left := mu.Left[string, int]("error") result := left.Fold( func(s string) int { return len(s) }, // onLeft func(x int) int { return x * 2 }, // onRight ) fmt.Println("Left(\"error\").Fold(len, x*2):", result) // Fold with Right value right := mu.Right[string, int](42) result2 := right.Fold( func(s string) int { return len(s) }, // onLeft func(x int) int { return x * 2 }, // onRight ) fmt.Println("Right(42).Fold(len, x*2):", result2) }
Output: Left("error").Fold(len, x*2): 5 Right(42).Fold(len, x*2): 84
func (Either[L, R]) IsLeft ¶
IsLeft returns true if the Either is a Left value.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // Create a Left value leftValue := mu.Left[string, int]("error") fmt.Println("Left(\"error\").IsLeft():", leftValue.IsLeft()) // Create a Right value rightValue := mu.Right[string, int](42) fmt.Println("Right(42).IsLeft():", rightValue.IsLeft()) }
Output: Left("error").IsLeft(): true Right(42).IsLeft(): false
func (Either[L, R]) IsRight ¶
IsRight returns true if the Either is a Right value.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // Create a Left value leftValue := mu.Left[string, int]("error") fmt.Println("Left(\"error\").IsRight():", leftValue.IsRight()) // Create a Right value rightValue := mu.Right[string, int](42) fmt.Println("Right(42).IsRight():", rightValue.IsRight()) }
Output: Left("error").IsRight(): false Right(42).IsRight(): true
func (Either[L, R]) Left ¶
Left returns the Left value as an `Option[L]`.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // Left with Left value left := mu.Left[string, int]("error message") leftOpt := left.Left() fmt.Println("Left(\"error message\").Left():", leftOpt.IsSome()) fmt.Println("Value:", leftOpt.OrZero()) // Left with Right value right := mu.Right[string, int](42) leftOpt2 := right.Left() fmt.Println("Right(42).Left():", leftOpt2.IsNone()) }
Output: Left("error message").Left(): true Value: error message Right(42).Left(): true
func (Either[L, R]) LeftOrElse ¶
func (e Either[L, R]) LeftOrElse(fallback L) L
LeftOrElse returns the contained Left value or the provided fallback value if the Either is a Right.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // LeftOrElse with Left value left := mu.Left[string, int]("error") result := left.LeftOrElse("fallback") fmt.Println("Left(\"error\").LeftOrElse(\"fallback\"):", result) // LeftOrElse with Right value right := mu.Right[string, int](42) result2 := right.LeftOrElse("fallback") fmt.Println("Right(42).LeftOrElse(\"fallback\"):", result2) }
Output: Left("error").LeftOrElse("fallback"): error Right(42).LeftOrElse("fallback"): fallback
func (Either[L, R]) LeftOrElseF ¶
func (e Either[L, R]) LeftOrElseF(fallback func() L) L
LeftOrElseF returns the contained Left value or computes it from a closure if the Either is a Right. The closure is lazily evaluated.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // LeftOrElseF with Left value left := mu.Left[string, int]("error") result := left.LeftOrElseF(func() string { return "fallback" }) fmt.Println("Left(\"error\").LeftOrElseF(func):", result) // LeftOrElseF with Right value right := mu.Right[string, int](42) result2 := right.LeftOrElseF(func() string { return "fallback" }) fmt.Println("Right(42).LeftOrElseF(func):", result2) }
Output: Left("error").LeftOrElseF(func): error Right(42).LeftOrElseF(func): fallback
func (Either[L, R]) LeftOrPanic ¶
func (e Either[L, R]) LeftOrPanic() L
LeftOrPanic returns the contained Left value. It panics if the Either is a Right.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // LeftOrPanic with Left value (safe) left := mu.Left[string, int]("error") result := left.LeftOrPanic() fmt.Println("Left(\"error\").LeftOrPanic():", result) // LeftOrPanic with Right would panic, so we show safe usage defer func() { if r := recover(); r != nil { fmt.Println("Right.LeftOrPanic() panicked:", r) } }() right := mu.Right[string, int](42) _ = right.LeftOrPanic() // This will panic }
Output: Left("error").LeftOrPanic(): error Right.LeftOrPanic() panicked: called LeftOrPanic() on Right
func (Either[L, R]) LeftOrZero ¶
func (e Either[L, R]) LeftOrZero() L
LeftOrZero returns the contained Left value or the zero value of type L if the Either is a Right.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // LeftOrZero with Left value left := mu.Left[string, int]("error") result := left.LeftOrZero() fmt.Println("Left(\"error\").LeftOrZero():", result) // LeftOrZero with Right value right := mu.Right[string, int](42) result2 := right.LeftOrZero() fmt.Println("Right(42).LeftOrZero():", result2) }
Output: Left("error").LeftOrZero(): error Right(42).LeftOrZero():
func (Either[L, R]) Map ¶
Map applies a function to a Right value, leaving a Left value untouched. For type-changing transformations (R→R2), use pkg/github.com/appthrust/mu/mue.MapTo instead. See package docs for details.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // Map with Right value right := mu.Right[string, int](42) mapped := right.Map(func(x int) int { return x * 2 }) fmt.Println("Right(42).Map(x*2):", mapped.OrZero()) // Map with Left value left := mu.Left[string, int]("error") mapped2 := left.Map(func(x int) int { return x * 2 }) fmt.Println("Left(\"error\").Map(x*2):", mapped2.LeftOrZero()) }
Output: Right(42).Map(x*2): 84 Left("error").Map(x*2): error
func (Either[L, R]) MapLeft ¶
MapLeft applies a function to a Left value, leaving a Right value untouched. For type-changing transformations (L→L2), use pkg/github.com/appthrust/mu/mue.MapLeftTo instead. See package docs for details.
Example ¶
package main import ( "fmt" "strings" "github.com/appthrust/mu" ) func main() { // MapLeft with Left value left := mu.Left[string, int]("error") mapped := left.MapLeft(func(s string) string { return strings.ToUpper(s) }) fmt.Println("Left(\"error\").MapLeft(upper):", mapped.LeftOrZero()) // MapLeft with Right value right := mu.Right[string, int](42) mapped2 := right.MapLeft(func(s string) string { return strings.ToUpper(s) }) fmt.Println("Right(42).MapLeft(upper):", mapped2.OrZero()) }
Output: Left("error").MapLeft(upper): ERROR Right(42).MapLeft(upper): 42
func (Either[L, R]) OrElse ¶
func (e Either[L, R]) OrElse(fallback R) R
OrElse returns the contained Right value or the provided fallback value if the Either is a Left.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // OrElse with Right value right := mu.Right[string, int](42) result := right.OrElse(100) fmt.Println("Right(42).OrElse(100):", result) // OrElse with Left value left := mu.Left[string, int]("error") result2 := left.OrElse(100) fmt.Println("Left(\"error\").OrElse(100):", result2) }
Output: Right(42).OrElse(100): 42 Left("error").OrElse(100): 100
func (Either[L, R]) OrElseF ¶
func (e Either[L, R]) OrElseF(fallback func() R) R
OrElseF returns the contained Right value or computes it from a closure if the Either is a Left. The closure is lazily evaluated.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // OrElseF with Right value right := mu.Right[string, int](42) result := right.OrElseF(func() int { return 100 }) fmt.Println("Right(42).OrElseF(func):", result) // OrElseF with Left value left := mu.Left[string, int]("error") result2 := left.OrElseF(func() int { return 100 }) fmt.Println("Left(\"error\").OrElseF(func):", result2) }
Output: Right(42).OrElseF(func): 42 Left("error").OrElseF(func): 100
func (Either[L, R]) OrPanic ¶
func (e Either[L, R]) OrPanic() R
OrPanic returns the contained Right value. It panics if the Either is a Left.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // OrPanic with Right value (safe) right := mu.Right[string, int](42) result := right.OrPanic() fmt.Println("Right(42).OrPanic():", result) // OrPanic with Left would panic, so we show safe usage defer func() { if r := recover(); r != nil { fmt.Println("Left.OrPanic() panicked:", r) } }() left := mu.Left[string, int]("error") _ = left.OrPanic() // This will panic }
Output: Right(42).OrPanic(): 42 Left.OrPanic() panicked: called OrPanic() on Left
func (Either[L, R]) OrZero ¶
func (e Either[L, R]) OrZero() R
OrZero returns the contained Right value or the zero value of type R if the Either is a Left.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // OrZero with Right value right := mu.Right[string, int](42) result := right.OrZero() fmt.Println("Right(42).OrZero():", result) // OrZero with Left value left := mu.Left[string, int]("error") result2 := left.OrZero() fmt.Println("Left(\"error\").OrZero():", result2) }
Output: Right(42).OrZero(): 42 Left("error").OrZero(): 0
func (Either[L, R]) Right ¶
Right returns the Right value as an `Option[R]`.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // Right with Right value right := mu.Right[string, int](42) rightOpt := right.Right() fmt.Println("Right(42).Right():", rightOpt.IsSome()) fmt.Println("Value:", rightOpt.OrZero()) // Right with Left value left := mu.Left[string, int]("error") rightOpt2 := left.Right() fmt.Println("Left(\"error\").Right():", rightOpt2.IsNone()) }
Output: Right(42).Right(): true Value: 42 Left("error").Right(): true
func (Either[L, R]) Swap ¶
Swap transforms an `Either[L, R]` into an `Either[R, L]`.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // Swap Left to Right left := mu.Left[string, int]("error message") swapped := left.Swap() fmt.Println("Left(\"error message\").Swap() is Right:", swapped.IsRight()) fmt.Println("Right value:", swapped.OrZero()) // Swap Right to Left right := mu.Right[string, int](42) swapped2 := right.Swap() fmt.Println("Right(42).Swap() is Left:", swapped2.IsLeft()) fmt.Println("Left value:", swapped2.LeftOrZero()) // Demonstrate type transformation: Either[string, int] -> Either[int, string] original := mu.Left[string, int]("hello") swapped3 := original.Swap() // Now Either[int, string] fmt.Println("Original Left(\"hello\") becomes Right:", swapped3.IsRight()) fmt.Println("New Right value:", swapped3.OrZero()) }
Output: Left("error message").Swap() is Right: true Right value: error message Right(42).Swap() is Left: true Left value: 42 Original Left("hello") becomes Right: true New Right value: hello
func (Either[L, R]) Tap ¶
Tap calls the given function with the contained Right value if the Either is a Right. It is used for side-effects and returns the original Either.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // Tap with Right value (executes side effect) right := mu.Right[string, int](42) result := right.Tap(func(x int) { fmt.Println("Processing right value:", x) }) fmt.Println("Right.Tap() returns same value:", result.OrZero()) // Tap with Left value (no side effect) left := mu.Left[string, int]("error") result2 := left.Tap(func(_ int) { fmt.Println("This won't be called") }) fmt.Println("Left.Tap() returns same value:", result2.LeftOrZero()) }
Output: Processing right value: 42 Right.Tap() returns same value: 42 Left.Tap() returns same value: error
func (Either[L, R]) TapLeft ¶
TapLeft calls the given function with the contained Left value if the Either is a Left. It is used for side-effects and returns the original Either.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // TapLeft with Left value (executes side effect) left := mu.Left[string, int]("error occurred") result := left.TapLeft(func(s string) { fmt.Println("Logging error:", s) }) fmt.Println("Left.TapLeft() returns same value:", result.LeftOrZero()) // TapLeft with Right value (no side effect) right := mu.Right[string, int](42) result2 := right.TapLeft(func(_ string) { fmt.Println("This won't be called") }) fmt.Println("Right.TapLeft() returns same value:", result2.OrZero()) }
Output: Logging error: error occurred Left.TapLeft() returns same value: error occurred Right.TapLeft() returns same value: 42
func (Either[L, R]) Unwrap ¶
Unwrap returns the Right value and a boolean indicating its presence.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // Unwrap with Right value right := mu.Right[string, int](42) value, ok := right.Unwrap() fmt.Println("Right(42).Unwrap():", value, ok) // Unwrap with Left value left := mu.Left[string, int]("error") value2, ok2 := left.Unwrap() fmt.Println("Left(\"error\").Unwrap():", value2, ok2) // Pattern matching with Either either := mu.Right[string, int](100) if rightVal, isRight := either.Unwrap(); isRight { fmt.Println("Got right value:", rightVal) } else if leftVal, isLeft := either.UnwrapLeft(); isLeft { fmt.Println("Got left value:", leftVal) } }
Output: Right(42).Unwrap(): 42 true Left("error").Unwrap(): 0 false Got right value: 100
func (Either[L, R]) UnwrapLeft ¶
UnwrapLeft returns the Left value and a boolean indicating its presence.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // UnwrapLeft with Left value left := mu.Left[string, int]("error message") value, ok := left.UnwrapLeft() fmt.Println("Left(\"error message\").UnwrapLeft():", value, ok) // UnwrapLeft with Right value right := mu.Right[string, int](42) value2, ok2 := right.UnwrapLeft() fmt.Println("Right(42).UnwrapLeft():", value2, ok2) }
Output: Left("error message").UnwrapLeft(): error message true Right(42).UnwrapLeft(): false
type Option ¶
type Option[T any] struct { // contains filtered or unexported fields }
Option represents an optional value: every `Option[T]` is either Some and contains a value, or None and does not. It provides a type-safe way to handle values that may be absent, avoiding the ambiguity of nil pointers for non-pointer types.
func None ¶
None returns an `Option[T]` that represents an absent value.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { value := mu.None[int]() fmt.Println("None[int]():", value.IsNone()) fmt.Println("Value:", value.OrZero()) }
Output: None[int](): true Value: 0
func Some ¶
Some returns an `Option[T]` that contains the given value.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { value := mu.Some(42) fmt.Println("Some(42):", value.IsSome()) fmt.Println("Value:", value.OrZero()) }
Output: Some(42): true Value: 42
func (Option[T]) Filter ¶
Filter returns the option if it is a Some and its value matches the predicate, otherwise returns None.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // Filter with Some value that matches predicate some42 := mu.Some(42) filtered := some42.Filter(func(x int) bool { return x > 40 }) fmt.Println("Some(42).Filter(>40):", filtered.IsSome()) fmt.Println("Value:", filtered.OrZero()) // Filter with Some value that doesn't match predicate filtered2 := some42.Filter(func(x int) bool { return x < 40 }) fmt.Println("Some(42).Filter(<40):", filtered2.IsNone()) // Filter with None value none := mu.None[int]() filtered3 := none.Filter(func(x int) bool { return x > 40 }) fmt.Println("None.Filter(>40):", filtered3.IsNone()) }
Output: Some(42).Filter(>40): true Value: 42 Some(42).Filter(<40): true None.Filter(>40): true
func (Option[T]) FlatMap ¶
FlatMap returns None if the option is None, otherwise calls the function with the wrapped value and returns the result. Used for chaining operations. For type-changing operations (T→U), use pkg/github.com/appthrust/mu/muo.FlatMapTo instead. See package docs for details.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // FlatMap with Some value some42 := mu.Some(42) result := some42.FlatMap(func(x int) mu.Option[int] { if x > 40 { return mu.Some(x * 2) } return mu.None[int]() }) fmt.Println("Some(42).FlatMap(x*2 if >40):", result.OrZero()) // FlatMap with None value none := mu.None[int]() result2 := none.FlatMap(func(x int) mu.Option[int] { return mu.Some(x * 2) }) fmt.Println("None.FlatMap(x*2):", result2.IsNone()) }
Output: Some(42).FlatMap(x*2 if >40): 84 None.FlatMap(x*2): true
func (Option[T]) Flatten ¶
Flatten converts an `Option[Option[T]]` into an `Option[T]`. This requires the inner type T to be an `Option[T]`.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // Note: Flatten works on properly nested Option types through type assertion // Create a nested Option[Option[int]] scenario innerSome := mu.Some(42) outerSome := mu.Some(innerSome) // For demonstration, we use the Flatten method which attempts type assertion result := outerSome.Flatten() fmt.Println("Nested Some contains value:", result.IsSome()) // Example with None inner value innerNone := mu.None[int]() outerWithNone := mu.Some(innerNone) result2 := outerWithNone.Flatten() fmt.Println("Nested with inner None:", result2.IsNone()) // Example with outer None outerNone := mu.None[mu.Option[int]]() result3 := outerNone.Flatten() fmt.Println("Outer None flattened:", result3.IsNone()) }
Output: Nested Some contains value: true Nested with inner None: false Outer None flattened: true
func (Option[T]) Fold ¶
func (o Option[T]) Fold(onSome func(T) T, onNone func() T) T
Fold applies the function f to the contained value of `Option[T]` if it exists, returning the result. If the option is None, it returns the result of the onNone function. For type-changing transformations (T→U), use pkg/github.com/appthrust/mu/muo.Fold instead. See package docs for details.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // Fold with Some value some42 := mu.Some(42) result := some42.Fold( func(x int) int { return x * 2 }, // onSome func() int { return -1 }, // onNone ) fmt.Println("Some(42).Fold(x*2, -1):", result) // Fold with None value none := mu.None[int]() result2 := none.Fold( func(x int) int { return x * 2 }, // onSome func() int { return -1 }, // onNone ) fmt.Println("None.Fold(x*2, -1):", result2) }
Output: Some(42).Fold(x*2, -1): 84 None.Fold(x*2, -1): -1
func (Option[T]) IsNone ¶
IsNone returns true if the option is a None value.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // Create a Some value someValue := mu.Some(42) fmt.Println("Some(42).IsNone():", someValue.IsNone()) // Create a None value noneValue := mu.None[int]() fmt.Println("None[int]().IsNone():", noneValue.IsNone()) }
Output: Some(42).IsNone(): false None[int]().IsNone(): true
func (Option[T]) IsSome ¶
IsSome returns true if the option is a Some value.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // Create a Some value someValue := mu.Some(42) fmt.Println("Some(42).IsSome():", someValue.IsSome()) // Create a None value noneValue := mu.None[int]() fmt.Println("None[int]().IsSome():", noneValue.IsSome()) }
Output: Some(42).IsSome(): true None[int]().IsSome(): false
func (Option[T]) Map ¶
Map applies a function to the contained value, transforming T to T. If the option is None, it returns `None[T]`. For type-changing transformations (T→U), use pkg/github.com/appthrust/mu/muo.MapTo instead. See package docs for details.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // Map with Some value some42 := mu.Some(42) mapped := some42.Map(func(x int) int { return x * 2 }) fmt.Println("Some(42).Map(x*2):", mapped.OrZero()) // Map with None value none := mu.None[int]() mapped2 := none.Map(func(x int) int { return x * 2 }) fmt.Println("None.Map(x*2):", mapped2.IsNone()) }
Output: Some(42).Map(x*2): 84 None.Map(x*2): true
func (Option[T]) OrElse ¶
func (o Option[T]) OrElse(fallback T) T
OrElse returns the contained Some value or the provided fallback value if the option is None.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // OrElse with Some value some42 := mu.Some(42) result := some42.OrElse(100) fmt.Println("Some(42).OrElse(100):", result) // OrElse with None value none := mu.None[int]() result2 := none.OrElse(100) fmt.Println("None.OrElse(100):", result2) }
Output: Some(42).OrElse(100): 42 None.OrElse(100): 100
func (Option[T]) OrElseF ¶
func (o Option[T]) OrElseF(fallback func() T) T
OrElseF returns the contained Some value or computes it from a closure if the option is None. The closure is lazily evaluated.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // OrElseF with Some value some42 := mu.Some(42) result := some42.OrElseF(func() int { return 100 }) fmt.Println("Some(42).OrElseF(func):", result) // OrElseF with None value none := mu.None[int]() result2 := none.OrElseF(func() int { return 100 }) fmt.Println("None.OrElseF(func):", result2) }
Output: Some(42).OrElseF(func): 42 None.OrElseF(func): 100
func (Option[T]) OrPanic ¶
func (o Option[T]) OrPanic() T
OrPanic returns the contained Some value. It panics if the option is None. OrPanic should only be used when the presence of a value is guaranteed by the program's logic.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // OrPanic with Some value (safe) some42 := mu.Some(42) result := some42.OrPanic() fmt.Println("Some(42).OrPanic():", result) // OrPanic with None would panic, so we show safe usage defer func() { if r := recover(); r != nil { fmt.Println("None.OrPanic() panicked:", r) } }() none := mu.None[int]() _ = none.OrPanic() // This will panic }
Output: Some(42).OrPanic(): 42 None.OrPanic() panicked: called OrPanic() on None
func (Option[T]) OrZero ¶
func (o Option[T]) OrZero() T
OrZero returns the contained Some value or the zero value of type T if the option is None.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // OrZero with Some value some42 := mu.Some(42) result := some42.OrZero() fmt.Println("Some(42).OrZero():", result) // OrZero with None value none := mu.None[int]() result2 := none.OrZero() fmt.Println("None.OrZero():", result2) // OrZero with string type someStr := mu.Some("hello") noneStr := mu.None[string]() fmt.Println("Some(\"hello\").OrZero():", someStr.OrZero()) fmt.Println("None[string].OrZero():", noneStr.OrZero()) }
Output: Some(42).OrZero(): 42 None.OrZero(): 0 Some("hello").OrZero(): hello None[string].OrZero():
func (Option[T]) Tap ¶
Tap calls the given function with the contained value if the option is Some. It is used for side-effects and returns the original `Option[T]`.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // Tap with Some value (executes side effect) some42 := mu.Some(42) result := some42.Tap(func(x int) { fmt.Println("Side effect: processing value", x) }) fmt.Println("Some(42).Tap() returns same value:", result.OrZero()) // Tap with None value (no side effect) none := mu.None[int]() result2 := none.Tap(func(_ int) { fmt.Println("This won't be called") }) fmt.Println("None.Tap() returns None:", result2.IsNone()) }
Output: Side effect: processing value 42 Some(42).Tap() returns same value: 42 None.Tap() returns None: true
func (Option[T]) ToResult ¶
ToResult converts the `Option[T]` to a `Result[T]`. If the option is Some, it returns `Ok(value)`. If it is None, it returns `Err(err)` with the provided error.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // ToResult with Some value some42 := mu.Some(42) result := some42.ToResult(errors.New("not found")) fmt.Println("Some(42).ToResult():", result.IsOk()) fmt.Println("Value:", result.OrZero()) // ToResult with None value none := mu.None[int]() result2 := none.ToResult(errors.New("value not found")) fmt.Println("None.ToResult():", result2.IsErr()) fmt.Println("Error:", result2.ErrOrZero().Error()) // Example use case: converting optional database result to Result userOpt := mu.Some("john_doe") userResult := userOpt.ToResult(errors.New("user not found")) fmt.Println("User found:", userResult.IsOk()) fmt.Println("Username:", userResult.OrElse("unknown")) // Another example with None emptyOpt := mu.None[string]() emptyResult := emptyOpt.ToResult(errors.New("no data available")) fmt.Println("Empty data:", emptyResult.IsErr()) fmt.Println("Fallback:", emptyResult.OrElse("default")) }
Output: Some(42).ToResult(): true Value: 42 None.ToResult(): true Error: value not found User found: true Username: john_doe Empty data: true Fallback: default
func (Option[T]) Unwrap ¶
Unwrap returns the contained value and a boolean indicating its presence.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { // Unwrap with Some value some42 := mu.Some(42) value, ok := some42.Unwrap() fmt.Println("Some(42).Unwrap():", value, ok) // Unwrap with None value none := mu.None[int]() value2, ok2 := none.Unwrap() fmt.Println("None.Unwrap():", value2, ok2) // Practical usage pattern if val, present := some42.Unwrap(); present { fmt.Println("Value is present:", val) } else { fmt.Println("Value is absent") } }
Output: Some(42).Unwrap(): 42 true None.Unwrap(): 0 false Value is present: 42
type Result ¶
type Result[T any] struct { // contains filtered or unexported fields }
Result represents either success (Ok) or failure (Err). The error type is fixed to Go's built-in `error` interface to ensure maximum compatibility with the standard library and existing Go code.
func Err ¶
Err returns a `Result[T]` that represents a failed operation with an error.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { result := mu.Err[int](errors.New("something went wrong")) fmt.Println("Err(error):", result.IsErr()) fmt.Println("Error:", result.ErrOrZero().Error()) }
Output: Err(error): true Error: something went wrong
func Ok ¶
Ok returns a `Result[T]` that represents a successful operation with a value.
Example ¶
package main import ( "fmt" "github.com/appthrust/mu" ) func main() { result := mu.Ok(42) fmt.Println("Ok(42):", result.IsOk()) fmt.Println("Value:", result.OrZero()) }
Output: Ok(42): true Value: 42
func Try ¶
Try executes a function that returns (T, error) and wraps the outcome in a `Result[T]`. If the function returns a nil error, it returns `Ok(value)`. If the function returns a non-nil error, it returns `Err(error)`.
Example ¶
package main import ( "fmt" "strconv" "github.com/appthrust/mu" ) func main() { // Success case successResult := mu.Try(func() (int, error) { return strconv.Atoi("42") }) fmt.Println("Try success:", successResult.IsOk()) fmt.Println("Value:", successResult.OrZero()) // Error case errorResult := mu.Try(func() (int, error) { return strconv.Atoi("not-a-number") }) fmt.Println("Try error:", errorResult.IsErr()) }
Output: Try success: true Value: 42 Try error: true
func Try0 ¶
Try0 executes a function that returns only an error and wraps the outcome in a `Result[Unit]`. If the function returns nil, it returns `Ok(UnitValue)`. If the function returns a non-nil error, it returns `Err(error)`. This is useful for operations that can fail but don't produce a meaningful value.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // Success case successResult := mu.Try0(func() error { // Some operation that might fail return nil }) fmt.Println("Try0 success:", successResult.IsOk()) // Error case errorResult := mu.Try0(func() error { return errors.New("operation failed") }) fmt.Println("Try0 error:", errorResult.IsErr()) fmt.Println("Error message:", errorResult.ErrOrZero().Error()) }
Output: Try0 success: true Try0 error: true Error message: operation failed
func (Result[T]) ErrOrElse ¶
ErrOrElse returns the contained Err value or the provided fallback value if the result is an Ok.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // ErrOrElse with Err value err := mu.Err[int](errors.New("original error")) result := err.ErrOrElse(errors.New("fallback error")) fmt.Println("Err.ErrOrElse(fallback):", result.Error()) // ErrOrElse with Ok value ok := mu.Ok(42) result2 := ok.ErrOrElse(errors.New("fallback error")) fmt.Println("Ok(42).ErrOrElse(fallback):", result2.Error()) }
Output: Err.ErrOrElse(fallback): original error Ok(42).ErrOrElse(fallback): fallback error
func (Result[T]) ErrOrElseF ¶
ErrOrElseF returns the contained Err value or computes it from a closure if the result is an Ok. The closure is lazily evaluated.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // ErrOrElseF with Err value err := mu.Err[int](errors.New("original error")) result := err.ErrOrElseF(func() error { return errors.New("fallback error") }) fmt.Println("Err.ErrOrElseF(func):", result.Error()) // ErrOrElseF with Ok value ok := mu.Ok(42) result2 := ok.ErrOrElseF(func() error { return errors.New("fallback error") }) fmt.Println("Ok(42).ErrOrElseF(func):", result2.Error()) }
Output: Err.ErrOrElseF(func): original error Ok(42).ErrOrElseF(func): fallback error
func (Result[T]) ErrOrPanic ¶
ErrOrPanic returns the contained Err value. It panics if the result is Ok.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // ErrOrPanic with Err value (safe) err := mu.Err[int](errors.New("something went wrong")) result := err.ErrOrPanic() fmt.Println("Err.ErrOrPanic():", result.Error()) // ErrOrPanic with Ok would panic, so we show safe usage defer func() { if r := recover(); r != nil { fmt.Println("Ok.ErrOrPanic() panicked:", r) } }() ok := mu.Ok(42) _ = ok.ErrOrPanic() // This will panic }
Output: Err.ErrOrPanic(): something went wrong Ok.ErrOrPanic() panicked: called ErrOrPanic() on Ok
func (Result[T]) ErrOrZero ¶
ErrOrZero returns the contained error if the result is an Err, otherwise nil.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // ErrOrZero with Err value err := mu.Err[int](errors.New("something went wrong")) result := err.ErrOrZero() fmt.Println("Err.ErrOrZero():", result.Error()) // ErrOrZero with Ok value ok := mu.Ok(42) result2 := ok.ErrOrZero() fmt.Println("Ok(42).ErrOrZero():", result2 == nil) }
Output: Err.ErrOrZero(): something went wrong Ok(42).ErrOrZero(): true
func (Result[T]) Error ¶
Error returns the error as an `Option[error]`.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // Error with Err err := mu.Err[int](errors.New("something went wrong")) errorOpt := err.Error() fmt.Println("Err.Error():", errorOpt.IsSome()) fmt.Println("Error message:", errorOpt.OrZero().Error()) // Error with Ok ok := mu.Ok(42) errorOpt2 := ok.Error() fmt.Println("Ok(42).Error():", errorOpt2.IsNone()) }
Output: Err.Error(): true Error message: something went wrong Ok(42).Error(): true
func (Result[T]) FlatMap ¶
FlatMap returns the original Err if the result is an Err, otherwise calls the function with the Ok value and returns the new Result[T]. For type-changing operations (T→U), use pkg/github.com/appthrust/mu/mur.FlatMapTo instead. See package docs for details.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // FlatMap with Ok value ok := mu.Ok(42) result := ok.FlatMap(func(x int) mu.Result[int] { if x > 40 { return mu.Ok(x * 2) } return mu.Err[int](errors.New("too small")) }) fmt.Println("Ok(42).FlatMap(x*2 if >40):", result.OrZero()) // FlatMap with Err value err := mu.Err[int](errors.New("initial error")) result2 := err.FlatMap(func(x int) mu.Result[int] { return mu.Ok(x * 2) }) fmt.Println("Err.FlatMap():", result2.ErrOrZero().Error()) }
Output: Ok(42).FlatMap(x*2 if >40): 84 Err.FlatMap(): initial error
func (Result[T]) FlatMapErr ¶
FlatMapErr applies a function to a contained Err value, returning a new Result. Used for error recovery operations. For type-changing operations (T→U), use pkg/github.com/appthrust/mu/mur.FlatMapErrTo instead. See package docs for details.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // FlatMapErr with Err value err := mu.Err[int](errors.New("connection failed")) result := err.FlatMapErr(func(e error) mu.Result[int] { if e.Error() == "connection failed" { return mu.Ok(42) // Recover from specific error } return mu.Err[int](e) }) fmt.Println("Err(\"connection failed\").FlatMapErr():", result.OrZero()) // FlatMapErr with Ok value ok := mu.Ok(42) result2 := ok.FlatMapErr(func(_ error) mu.Result[int] { return mu.Ok(0) }) fmt.Println("Ok(42).FlatMapErr():", result2.OrZero()) }
Output: Err("connection failed").FlatMapErr(): 42 Ok(42).FlatMapErr(): 42
func (Result[T]) Flatten ¶
Flatten converts an `Result[Result[T]]` into an `Result[T]`. This requires the inner type T to be an `Result[T]`.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // Note: Flatten works on properly nested Result types through type assertion // Create nested Result scenario innerOk := mu.Ok(42) outerOk := mu.Ok(innerOk) result := outerOk.Flatten() fmt.Println("Nested Ok contains value:", result.IsOk()) fmt.Println("Value:", result.OrZero()) // Example with inner Err innerErr := mu.Err[int](errors.New("inner error")) outerWithErr := mu.Ok(innerErr) result2 := outerWithErr.Flatten() fmt.Println("Nested with inner Err:", result2.IsErr()) if result2.IsErr() { fmt.Println("Error:", result2.ErrOrZero().Error()) } // Example with outer Err outerErr := mu.Err[mu.Result[int]](errors.New("outer error")) result3 := outerErr.Flatten() fmt.Println("Outer Err flattened:", result3.IsErr()) if result3.IsErr() { fmt.Println("Error:", result3.ErrOrZero().Error()) } }
Output: Nested Ok contains value: true Value: {42 <nil>} Nested with inner Err: false Outer Err flattened: true Error: outer error
func (Result[T]) Fold ¶
Fold applies the function f to the contained value of Result[T] if it is Ok, returning the result. If the result is Err, it returns the result of the onErr function. For type-changing transformations (T→U), use mur.Fold instead. See package docs for details.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // Fold with Ok value ok := mu.Ok(42) result := ok.Fold( func(x int) int { return x * 2 }, // onOk func(e error) int { return len(e.Error()) }, // onErr ) fmt.Println("Ok(42).Fold(x*2, len(err)):", result) // Fold with Err value err := mu.Err[int](errors.New("error")) result2 := err.Fold( func(x int) int { return x * 2 }, // onOk func(e error) int { return len(e.Error()) }, // onErr ) fmt.Println("Err(\"error\").Fold(x*2, len(err)):", result2) }
Output: Ok(42).Fold(x*2, len(err)): 84 Err("error").Fold(x*2, len(err)): 5
func (Result[T]) IsErr ¶
IsErr returns true if the result is Err.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // Create an Ok value okValue := mu.Ok(42) fmt.Println("Ok(42).IsErr():", okValue.IsErr()) // Create an Err value errValue := mu.Err[int](errors.New("something went wrong")) fmt.Println("Err(error).IsErr():", errValue.IsErr()) }
Output: Ok(42).IsErr(): false Err(error).IsErr(): true
func (Result[T]) IsOk ¶
IsOk returns true if the result is Ok.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // Create an Ok value okValue := mu.Ok(42) fmt.Println("Ok(42).IsOk():", okValue.IsOk()) // Create an Err value errValue := mu.Err[int](errors.New("something went wrong")) fmt.Println("Err(error).IsOk():", errValue.IsOk()) }
Output: Ok(42).IsOk(): true Err(error).IsOk(): false
func (Result[T]) Map ¶
Map applies a function to a contained Ok value, leaving an Err value untouched. For type-changing transformations (T→U), use pkg/github.com/appthrust/mu/mur.MapTo instead. See package docs for details.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // Map with Ok value ok := mu.Ok(42) mapped := ok.Map(func(x int) int { return x * 2 }) fmt.Println("Ok(42).Map(x*2):", mapped.OrZero()) // Map with Err value err := mu.Err[int](errors.New("error")) mapped2 := err.Map(func(x int) int { return x * 2 }) fmt.Println("Err.Map(x*2):", mapped2.ErrOrZero().Error()) }
Output: Ok(42).Map(x*2): 84 Err.Map(x*2): error
func (Result[T]) MapErr ¶
MapErr applies a function to a contained Err value, leaving an Ok value untouched.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // MapErr with Err value err := mu.Err[int](errors.New("connection failed")) mapped := err.MapErr(func(e error) error { return errors.New("wrapped: " + e.Error()) }) fmt.Println("Err.MapErr(wrap):", mapped.ErrOrZero().Error()) // MapErr with Ok value ok := mu.Ok(42) mapped2 := ok.MapErr(func(e error) error { return errors.New("wrapped: " + e.Error()) }) fmt.Println("Ok(42).MapErr(wrap):", mapped2.OrZero()) }
Output: Err.MapErr(wrap): wrapped: connection failed Ok(42).MapErr(wrap): 42
func (Result[T]) OrElse ¶
func (r Result[T]) OrElse(fallback T) T
OrElse returns the contained Ok value or the provided fallback value if the result is an Err.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // OrElse with Ok value ok := mu.Ok(42) result := ok.OrElse(100) fmt.Println("Ok(42).OrElse(100):", result) // OrElse with Err value err := mu.Err[int](errors.New("error")) result2 := err.OrElse(100) fmt.Println("Err.OrElse(100):", result2) }
Output: Ok(42).OrElse(100): 42 Err.OrElse(100): 100
func (Result[T]) OrElseF ¶
func (r Result[T]) OrElseF(fallback func() T) T
OrElseF returns the contained Ok value or computes it from a closure if the result is an Err. The closure is lazily evaluated.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // OrElseF with Ok value ok := mu.Ok(42) result := ok.OrElseF(func() int { return 100 }) fmt.Println("Ok(42).OrElseF(func):", result) // OrElseF with Err value err := mu.Err[int](errors.New("error")) result2 := err.OrElseF(func() int { return 100 }) fmt.Println("Err.OrElseF(func):", result2) }
Output: Ok(42).OrElseF(func): 42 Err.OrElseF(func): 100
func (Result[T]) OrPanic ¶
func (r Result[T]) OrPanic() T
OrPanic returns the contained Ok value. It panics if the result is an Err. This should be used only when an Ok value is guaranteed.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // OrPanic with Ok value (safe) ok := mu.Ok(42) result := ok.OrPanic() fmt.Println("Ok(42).OrPanic():", result) // OrPanic with Err would panic, so we show safe usage defer func() { if r := recover(); r != nil { fmt.Println("Err.OrPanic() panicked:", r) } }() err := mu.Err[int](errors.New("error")) _ = err.OrPanic() // This will panic }
Output: Ok(42).OrPanic(): 42 Err.OrPanic() panicked: called OrPanic() on Err
func (Result[T]) OrZero ¶
func (r Result[T]) OrZero() T
OrZero returns the contained Ok value or the zero value of type T if the result is an Err.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // OrZero with Ok value ok := mu.Ok(42) result := ok.OrZero() fmt.Println("Ok(42).OrZero():", result) // OrZero with Err value err := mu.Err[int](errors.New("error")) result2 := err.OrZero() fmt.Println("Err.OrZero():", result2) // OrZero with string type okStr := mu.Ok("hello") errStr := mu.Err[string](errors.New("error")) fmt.Println("Ok(\"hello\").OrZero():", okStr.OrZero()) fmt.Println("Err[string].OrZero():", errStr.OrZero()) }
Output: Ok(42).OrZero(): 42 Err.OrZero(): 0 Ok("hello").OrZero(): hello Err[string].OrZero():
func (Result[T]) Recover ¶
Recover maps an Err to an Ok value by applying a recovery function to the error. An Ok value is returned unchanged.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // Recover from Err value err := mu.Err[int](errors.New("connection failed")) recovered := err.Recover(func(e error) int { // Provide a default value when there's an error if e.Error() == "connection failed" { return 42 // Default value for connection errors } return 0 }) fmt.Println("Err.Recover():", recovered.OrZero()) // Recover with Ok value (no change) ok := mu.Ok(100) recovered2 := ok.Recover(func(_ error) int { return 42 }) fmt.Println("Ok(100).Recover():", recovered2.OrZero()) }
Output: Err.Recover(): 42 Ok(100).Recover(): 100
func (Result[T]) RecoverF ¶
RecoverF maps an Err to a new `Result[T]` by applying a recovery function. This allows for fallback operations that may themselves fail.
Example ¶
package main import ( "errors" "fmt" "strconv" "github.com/appthrust/mu" ) func main() { // RecoverF from Err value with fallback operation that might also fail err := mu.Err[int](errors.New("primary operation failed")) recovered := err.RecoverF(func(_ error) mu.Result[int] { // Try alternative operation return mu.Try(func() (int, error) { return strconv.Atoi("42") // Fallback: parse from string }) }) fmt.Println("Err.RecoverF() success:", recovered.IsOk()) fmt.Println("Value:", recovered.OrZero()) // RecoverF with fallback that also fails err2 := mu.Err[int](errors.New("primary operation failed")) recovered2 := err2.RecoverF(func(_ error) mu.Result[int] { // Alternative operation that also fails return mu.Try(func() (int, error) { return strconv.Atoi("not-a-number") }) }) fmt.Println("Err.RecoverF() failed:", recovered2.IsErr()) // RecoverF with Ok value (no change) ok := mu.Ok(100) recovered3 := ok.RecoverF(func(_ error) mu.Result[int] { return mu.Ok(42) }) fmt.Println("Ok(100).RecoverF():", recovered3.OrZero()) }
Output: Err.RecoverF() success: true Value: 42 Err.RecoverF() failed: true Ok(100).RecoverF(): 100
func (Result[T]) Tap ¶
Tap calls the given function with the contained value if the result is Ok. It is used for side-effects and returns the original Result.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // Tap with Ok value (executes side effect) ok := mu.Ok(42) result := ok.Tap(func(x int) { fmt.Println("Processing successful result:", x) }) fmt.Println("Ok.Tap() returns same value:", result.OrZero()) // Tap with Err value (no side effect) err := mu.Err[int](errors.New("operation failed")) result2 := err.Tap(func(_ int) { fmt.Println("This won't be called") }) fmt.Println("Err.Tap() returns same error:", result2.ErrOrZero().Error()) }
Output: Processing successful result: 42 Ok.Tap() returns same value: 42 Err.Tap() returns same error: operation failed
func (Result[T]) TapErr ¶
TapErr calls the given function with the contained error if the result is Err. It is used for side-effects (like logging) and returns the original Result.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // TapErr with Err value (executes side effect) err := mu.Err[int](errors.New("operation failed")) result := err.TapErr(func(e error) { fmt.Println("Logging error:", e.Error()) }) fmt.Println("Err.TapErr() returns same error:", result.ErrOrZero().Error()) // TapErr with Ok value (no side effect) ok := mu.Ok(42) result2 := ok.TapErr(func(_ error) { fmt.Println("This won't be called") }) fmt.Println("Ok.TapErr() returns same value:", result2.OrZero()) }
Output: Logging error: operation failed Err.TapErr() returns same error: operation failed Ok.TapErr() returns same value: 42
func (Result[T]) Unpack ¶
Unpack converts Result[T] back to Go's standard (value, error) pattern. If the Result is Ok, returns (value, nil). If the Result is Err, returns (zero_value, error).
Example ¶
ExampleResult_Unpack demonstrates converting Result back to Go's (value, error) pattern
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // Ok result unpacks to (value, nil) okResult := mu.Ok(42) value, err := okResult.Unpack() fmt.Printf("Ok result: value=%d, err=%v\n", value, err) // Err result unpacks to (zero_value, error) errResult := mu.Err[int](errors.New("something went wrong")) value, err = errResult.Unpack() fmt.Printf("Err result: value=%d, err=%v\n", value, err) }
Output: Ok result: value=42, err=<nil> Err result: value=0, err=something went wrong
Example (BridgeToLegacyCode) ¶
ExampleResult_Unpack_bridgeToLegacyCode shows bridging mu.Result to legacy Go code
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // Legacy function that expects (value, error) processData := func(data string, err error) { if err != nil { fmt.Printf("Processing failed: %v\n", err) return } fmt.Printf("Processing: %s\n", data) } // Modern function that returns Result fetchData := func(id int) mu.Result[string] { if id <= 0 { return mu.Err[string](errors.New("invalid ID")) } return mu.Ok(fmt.Sprintf("data-%d", id)) } // Bridge between modern and legacy code data, err := fetchData(123).Unpack() processData(data, err) data, err = fetchData(-1).Unpack() processData(data, err) }
Output: Processing: data-123 Processing failed: invalid ID
Example (WithFunctions) ¶
ExampleResult_Unpack_withFunctions demonstrates using Unpack with functions
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // Function that returns Result divide := func(a, b int) mu.Result[int] { if b == 0 { return mu.Err[int](errors.New("division by zero")) } return mu.Ok(a / b) } // Convert Result back to Go pattern for traditional error handling handleDivision := func(a, b int) { value, err := divide(a, b).Unpack() if err != nil { fmt.Printf("Error: %v\n", err) return } fmt.Printf("Result: %d\n", value) } handleDivision(10, 2) handleDivision(10, 0) }
Output: Result: 5 Error: division by zero
func (Result[T]) Unwrap ¶
Unwrap returns the value and a boolean indicating its presence.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // Unwrap with Ok value ok := mu.Ok(42) value, isOk := ok.Unwrap() fmt.Println("Ok(42).Unwrap():", value, isOk) // Unwrap with Err value err := mu.Err[int](errors.New("operation failed")) value2, isOk2 := err.Unwrap() fmt.Println("Err.Unwrap():", value2, isOk2) // Error handling pattern result := mu.Ok(200) if val, success := result.Unwrap(); success { fmt.Println("Operation succeeded with value:", val) } else { fmt.Println("Operation failed") } }
Output: Ok(42).Unwrap(): 42 true Err.Unwrap(): 0 false Operation succeeded with value: 200
func (Result[T]) UnwrapErr ¶
UnwrapErr returns the error and a boolean indicating its presence.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // UnwrapErr with Err value err := mu.Err[int](errors.New("something went wrong")) errValue, hasErr := err.UnwrapErr() fmt.Println("Err.UnwrapErr():", errValue.Error(), hasErr) // UnwrapErr with Ok value ok := mu.Ok(42) errValue2, hasErr2 := ok.UnwrapErr() fmt.Println("Ok(42).UnwrapErr():", errValue2 == nil, hasErr2) // Error handling with UnwrapErr result := mu.Err[string](errors.New("network timeout")) if e, hasError := result.UnwrapErr(); hasError { fmt.Println("Error occurred:", e.Error()) } else { fmt.Println("No error") } }
Output: Err.UnwrapErr(): something went wrong true Ok(42).UnwrapErr(): true false Error occurred: network timeout
func (Result[T]) Value ¶
Value returns the value as an `Option[T]`.
Example ¶
package main import ( "errors" "fmt" "github.com/appthrust/mu" ) func main() { // Value with Ok ok := mu.Ok(42) valueOpt := ok.Value() fmt.Println("Ok(42).Value():", valueOpt.IsSome()) fmt.Println("Value:", valueOpt.OrZero()) // Value with Err err := mu.Err[int](errors.New("something went wrong")) valueOpt2 := err.Value() fmt.Println("Err.Value():", valueOpt2.IsNone()) }
Output: Ok(42).Value(): true Value: 42 Err.Value(): true
Source Files
¶
Directories
¶
Path | Synopsis |
---|---|
Package mue provides type-changing utility functions for `Either[L,R]`.
|
Package mue provides type-changing utility functions for `Either[L,R]`. |
Package muo provides type-changing utility functions for `Option[T]`.
|
Package muo provides type-changing utility functions for `Option[T]`. |
Package mur provides type-changing utility functions for `Result[T]`.
|
Package mur provides type-changing utility functions for `Result[T]`. |