Skip to content

Commit

Permalink
Add UnwrapOr* functions (#40)
Browse files Browse the repository at this point in the history
Added `UnwrapOr`, `UnwrapOrElse` and `UnwrapOrDefault` functions to
`Option` & `Result` types.
  • Loading branch information
Dean Karn authored Oct 18, 2023
1 parent b9698f8 commit c86469e
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 2 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [5.21.3] - 2023-10-18
### Added
- `UnwrapOr`, `UnwrapOrElse` and `UnwrapOrDefault` functions to `Option` & `Result` types.

## [5.21.3] - 2023-10-11
### Fixed
- Fix SQL Scanner interface not returning None for Option when source data is nil.
Expand Down Expand Up @@ -78,7 +82,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Added `timext.NanoTime` for fast low level monotonic time with nanosecond precision.

[Unreleased]: https://github.com/go-playground/pkg/compare/v5.21.3...HEAD
[Unreleased]: https://github.com/go-playground/pkg/compare/v5.22.0...HEAD
[5.22.0]: https://github.com/go-playground/pkg/compare/v5.21.3..v5.22.0
[5.21.3]: https://github.com/go-playground/pkg/compare/v5.21.2..v5.21.3
[5.21.2]: https://github.com/go-playground/pkg/compare/v5.21.1..v5.21.2
[5.21.1]: https://github.com/go-playground/pkg/compare/v5.21.0..v5.21.1
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# pkg

![Project status](https://img.shields.io/badge/version-5.21.3-green.svg)
![Project status](https://img.shields.io/badge/version-5.22.0-green.svg)
[![Lint & Test](https://github.com/go-playground/pkg/actions/workflows/go.yml/badge.svg)](https://github.com/go-playground/pkg/actions/workflows/go.yml)
[![Coverage Status](https://coveralls.io/repos/github/go-playground/pkg/badge.svg?branch=master)](https://coveralls.io/github/go-playground/pkg?branch=master)
[![GoDoc](https://godoc.org/github.com/go-playground/pkg?status.svg)](https://pkg.go.dev/mod/github.com/go-playground/pkg/v5)
Expand Down
24 changes: 24 additions & 0 deletions values/option/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,30 @@ func (o Option[T]) Unwrap() T {
panic("Option.Unwrap: option is None")
}

// UnwrapOr returns the contained `Some` value or provided default value.
//
// Arguments passed to `UnwrapOr` are eagerly evaluated; if you are passing the result of a function call,
// look to use `UnwrapOrElse`, which can be lazily evaluated.
func (o Option[T]) UnwrapOr(value T) T {
if o.isSome {
return o.value
}
return value
}

// UnwrapOrElse returns the contained `Some` value or computes it from a provided function.
func (o Option[T]) UnwrapOrElse(fn func() T) T {
if o.isSome {
return o.value
}
return fn()
}

// UnwrapOrDefault returns the contained `Some` value or the default value of the type T.
func (o Option[T]) UnwrapOrDefault() T {
return o.value
}

// Some creates a new Option with the given values.
func Some[T any](value T) Option[T] {
return Option[T]{value, true}
Expand Down
31 changes: 31 additions & 0 deletions values/option/option_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,37 @@ type testStructType struct {
Name string
}

func TestUnwraps(t *testing.T) {
none := None[int]()
PanicMatches(t, func() { none.Unwrap() }, "Option.Unwrap: option is None")

v := none.UnwrapOr(3)
Equal(t, 3, v)

v = none.UnwrapOrElse(func() int { return 2 })
Equal(t, 2, v)

v = none.UnwrapOrDefault()
Equal(t, 0, v)

// now test with a pointer type.
type myStruct struct {
S string
}

sNone := None[*myStruct]()
PanicMatches(t, func() { sNone.Unwrap() }, "Option.Unwrap: option is None")

v2 := sNone.UnwrapOr(&myStruct{S: "blah"})
Equal(t, &myStruct{S: "blah"}, v2)

v2 = sNone.UnwrapOrElse(func() *myStruct { return &myStruct{S: "blah 2"} })
Equal(t, &myStruct{S: "blah 2"}, v2)

v2 = sNone.UnwrapOrDefault()
Equal(t, nil, v2)
}

func TestSQLDriverValue(t *testing.T) {

var v valueTest
Expand Down
24 changes: 24 additions & 0 deletions values/result/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,30 @@ func (r Result[T, E]) Unwrap() T {
panic("Result.Unwrap(): result is Err")
}

// UnwrapOr returns the contained Ok value or a provided default.
//
// Arguments passed to UnwrapOr are eagerly evaluated; if you are passing the result of a function call,
// look to use `UnwrapOrElse`, which can be lazily evaluated.
func (r Result[T, E]) UnwrapOr(value T) T {
if r.isOk {
return r.ok
}
return value
}

// UnwrapOrElse returns the contained Ok value or computes it from a provided function.
func (r Result[T, E]) UnwrapOrElse(fn func() T) T {
if r.isOk {
return r.ok
}
return fn()
}

// UnwrapOrDefault returns the contained Ok value or the default value of the type T.
func (r Result[T, E]) UnwrapOrDefault() T {
return r.ok
}

// Err returns the error of the result. To be used after calling IsOK()
func (r Result[T, E]) Err() E {
return r.err
Expand Down
15 changes: 15 additions & 0 deletions values/result/result_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,28 @@ package resultext

import (
"errors"
"io"
"testing"

. "github.com/go-playground/assert/v2"
)

type myStruct struct{}

func TestUnwrap(t *testing.T) {
er := Err[int, error](io.EOF)
PanicMatches(t, func() { er.Unwrap() }, "Result.Unwrap(): result is Err")

v := er.UnwrapOr(3)
Equal(t, 3, v)

v = er.UnwrapOrElse(func() int { return 2 })
Equal(t, 2, v)

v = er.UnwrapOrDefault()
Equal(t, 0, v)
}

func TestResult(t *testing.T) {
result := returnOk()
Equal(t, true, result.IsOk())
Expand Down

0 comments on commit c86469e

Please sign in to comment.