result.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. package fn
  2. import (
  3. "fmt"
  4. "testing"
  5. )
  6. // Result represents a value that can either be a success (T) or an error.
  7. type Result[T any] struct {
  8. Either[T, error]
  9. }
  10. // Ok creates a new Result with a success value.
  11. func Ok[T any](val T) Result[T] {
  12. return Result[T]{Either: NewLeft[T, error](val)}
  13. }
  14. // Err creates a new Result with an error.
  15. func Err[T any](err error) Result[T] {
  16. return Result[T]{Either: NewRight[T, error](err)}
  17. }
  18. // Errf creates a new Result with a new formatted error string.
  19. func Errf[T any](errString string, args ...any) Result[T] {
  20. return Result[T]{
  21. Either: NewRight[T, error](fmt.Errorf(errString, args...)),
  22. }
  23. }
  24. // Unpack extracts the value or error from the Result.
  25. func (r Result[T]) Unpack() (T, error) {
  26. var zero T
  27. return r.left.UnwrapOr(zero), r.right.UnwrapOr(nil)
  28. }
  29. // IsOk returns true if the Result is a success value.
  30. func (r Result[T]) IsOk() bool {
  31. return r.IsLeft()
  32. }
  33. // IsErr returns true if the Result is an error.
  34. func (r Result[T]) IsErr() bool {
  35. return r.IsRight()
  36. }
  37. // Map applies a function to the success value if it exists.
  38. func (r Result[T]) Map(f func(T) T) Result[T] {
  39. if r.IsOk() {
  40. return Ok(f(r.left.some))
  41. }
  42. return r
  43. }
  44. // MapErr applies a function to the error value if it exists.
  45. func (r Result[T]) MapErr(f func(error) error) Result[T] {
  46. if r.IsErr() {
  47. return Err[T](f(r.right.some))
  48. }
  49. return r
  50. }
  51. // Option returns the success value as an Option.
  52. func (r Result[T]) Option() Option[T] {
  53. return r.left
  54. }
  55. // WhenResult executes the given function if the Result is a success.
  56. func (r Result[T]) WhenResult(f func(T)) {
  57. r.left.WhenSome(func(t T) {
  58. f(t)
  59. })
  60. }
  61. // WhenErr executes the given function if the Result is an error.
  62. func (r Result[T]) WhenErr(f func(error)) {
  63. r.right.WhenSome(func(e error) {
  64. f(e)
  65. })
  66. }
  67. // UnwrapOr returns the success value or a default value if it's an error.
  68. func (r Result[T]) UnwrapOr(defaultValue T) T {
  69. return r.left.UnwrapOr(defaultValue)
  70. }
  71. // UnwrapOrElse returns the success value or computes a value from a function
  72. // if it's an error.
  73. func (r Result[T]) UnwrapOrElse(f func() T) T {
  74. return r.left.UnwrapOrFunc(f)
  75. }
  76. // UnwrapOrFail returns the success value or fails the test if it's an error.
  77. func (r Result[T]) UnwrapOrFail(t *testing.T) T {
  78. t.Helper()
  79. return r.left.UnwrapOrFail(t)
  80. }
  81. // FlatMap applies a function that returns a Result to the success value if it
  82. // exists.
  83. func (r Result[T]) FlatMap(f func(T) Result[T]) Result[T] {
  84. if r.IsOk() {
  85. return f(r.left.some)
  86. }
  87. return r
  88. }
  89. // AndThen is an alias for FlatMap. This along with OrElse can be used to
  90. // Railway Oriented Programming (ROP) by chaining successive computational
  91. // operations from a single result type.
  92. func (r Result[T]) AndThen(f func(T) Result[T]) Result[T] {
  93. return r.FlatMap(f)
  94. }
  95. // OrElse returns the original Result if it is a success, otherwise it returns
  96. // the provided alternative Result. This along with AndThen can be used to
  97. // Railway Oriented Programming (ROP).
  98. func (r Result[T]) OrElse(f func() Result[T]) Result[T] {
  99. if r.IsOk() {
  100. return r
  101. }
  102. return f()
  103. }
  104. // FlatMap applies a function that returns a Result[B] to the success value if
  105. // it exists.
  106. func FlatMap[A, B any](r Result[A], f func(A) Result[B]) Result[B] {
  107. if r.IsOk() {
  108. return f(r.left.some)
  109. }
  110. return Err[B](r.right.some)
  111. }
  112. // AndThen is an alias for FlatMap. This along with OrElse can be used to
  113. // Railway Oriented Programming (ROP).
  114. func AndThen[A, B any](r Result[A], f func(A) Result[B]) Result[B] {
  115. return FlatMap(r, f)
  116. }