optional

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: May 27, 2022 License: MIT Imports: 1 Imported by: 39

README

go-optional .github/workflows/check.yml codecov

A library that provides Go Generics friendly "optional" features.

Synopsis

some := optional.Some[int](123)
fmt.Printf("%v\n", some.IsSome()) // => true
fmt.Printf("%v\n", some.IsNone()) // => false

v, err := some.Take()
fmt.Printf("err is nil: %v\n", err == nil) // => err is nil: true
fmt.Printf("%d\n", v) // => 123

mapped := optional.Map(some, func (v int) int {
    return v * 2
})
fmt.Printf("%v\n", mapped.IsSome()) // => true

mappedValue, _ := some.Take()
fmt.Printf("%d\n", mappedValue) // => 246
none := optional.None[int]()
fmt.Printf("%v\n", none.IsSome()) // => false
fmt.Printf("%v\n", none.IsNone()) // => true

_, err := none.Take()
fmt.Printf("err is nil: %v\n", err == nil) // => err is nil: false
// the error must be `ErrNoneValueTaken`

mapped := optional.Map(none, func (v int) int {
    return v * 2
})
fmt.Printf("%v\n", mapped.IsNone()) // => true

and more detailed examples are here.

Also you can try this on The Go Playground for gotip: https://gotipplay.golang.org/p/mWGdFIfcK8c

Docs

GoDoc

Tips

  • it would be better to deal with an Option value as a non-pointer because if the Option value can accept nil it becomes worthless

Current Status

Currently (at the moment: Nov 18, 2021), go 1.18 has not been released yet, so if you'd like to try this, please use the tip runtime.
Of course, the new runtime version hasn't been released yet so this library has the possibility to change the implementation as well.

Known Issues

The runtime raises a compile error like "methods cannot have type parameters", so Map(), MapOr(), MapWithError(), MapOrWithError(), Zip(), ZipWith(), Unzip() and UnzipWith() have been providing as functions. Basically, it would be better to provide them as the methods, but currently, it compromises with the limitation.

Author

moznion (moznion@mail.moznion.net)

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrNoneValueTaken represents the error that is raised when None value is taken.
	ErrNoneValueTaken = errors.New("none value taken")
)

Functions

func MapOr

func MapOr[T, U any](option Option[T], fallbackValue U, mapper func(v T) U) U

MapOr converts given Option value to another *actual* value according to the mapper function. If given Option value is None, this returns fallbackValue.

Example
mapper := func(v int) string {
	return fmt.Sprintf("%d", v)
}

some := Some[int](1)
mapped := MapOr(some, "N/A", mapper)
fmt.Printf("%s\n", mapped)

none := None[int]()
mapped = MapOr(none, "N/A", mapper)
fmt.Printf("%s\n", mapped)
Output:
1
N/A

func MapOrWithError added in v0.1.0

func MapOrWithError[T, U any](option Option[T], fallbackValue U, mapper func(v T) (U, error)) (U, error)

MapOrWithError converts given Option value to another *actual* value according to the mapper function that has the ability to return the value with an error. If given Option value is None, this returns (fallbackValue, nil). Else if the mapper returns an error then returns (_, error). Unless of them, i.e. given Option value is Some and the mapper doesn't return the error, this returns (U, nil).

Example
mapperWithNoError := func(v int) (string, error) {
	return fmt.Sprintf("%d", v), nil
}

some := Some[int](1)
mapped, err := MapOrWithError(some, "N/A", mapperWithNoError)
fmt.Printf("err is nil: %v\n", err == nil)
fmt.Printf("%s\n", mapped)

none := None[int]()
mapped, err = MapOrWithError(none, "N/A", mapperWithNoError)
fmt.Printf("err is nil: %v\n", err == nil)
fmt.Printf("%s\n", mapped)

mapperWithError := func(v int) (string, error) {
	return "<ignore-me>", errors.New("something wrong")
}
mapped, err = MapOrWithError(some, "N/A", mapperWithError)
fmt.Printf("err is nil: %v\n", err == nil)
fmt.Printf("%s\n", mapped)
Output:
err is nil: true
1
err is nil: true
N/A
err is nil: false
<ignore-me>

func Unzip

func Unzip[T, U any](zipped Option[Pair[T, U]]) (Option[T], Option[U])

Unzip extracts the values from a Pair and pack them into each Option value. If the given zipped value is None, this returns None for all return values.

Example
// see also ExampleZip()

pair := Pair[int, string]{
	Value1: 123,
	Value2: "foo",
}

o1, o2 := Unzip(Some[Pair[int, string]](pair))
fmt.Printf("%d\n", o1.TakeOr(0))
fmt.Printf("%s\n", o2.TakeOr(""))

o1, o2 = Unzip(None[Pair[int, string]]())
fmt.Printf("is none => %v\n", o1.IsNone())
fmt.Printf("is none => %v\n", o2.IsNone())
Output:
123
foo
is none => true
is none => true

func UnzipWith

func UnzipWith[T, U, V any](zipped Option[V], unzipper func(zipped V) (T, U)) (Option[T], Option[U])

UnzipWith extracts the values from the given value according to the unzipper function and pack the into each Option value. If the given zipped value is None, this returns None for all return values.

Example
// see also ExampleZipWith()

type Data struct {
	A int
	B string
}

unzipper := func(d Data) (int, string) {
	return d.A, d.B
}

o1, o2 := UnzipWith(Some[Data](Data{
	A: 123,
	B: "foo",
}), unzipper)
fmt.Printf("%d\n", o1.TakeOr(0))
fmt.Printf("%s\n", o2.TakeOr(""))

o1, o2 = UnzipWith(None[Data](), unzipper)
fmt.Printf("is none => %v\n", o1.IsNone())
fmt.Printf("is none => %v\n", o2.IsNone())
Output:
123
foo
is none => true
is none => true

Types

type Option

type Option[T any] struct {
	// contains filtered or unexported fields
}

Option is a data type that must be Some (i.e. having a value) or None (i.e. doesn't have a value).

func Map

func Map[T, U any](option Option[T], mapper func(v T) U) Option[U]

Map converts given Option value to another Option value according to the mapper function. If given Option value is None, this also returns None.

Example
mapper := func(v int) string {
	return fmt.Sprintf("%d", v)
}

some := Some[int](1)
opt := Map(some, mapper)
fmt.Printf("%s\n", opt.TakeOr("N/A"))

none := None[int]()
opt = Map(none, mapper)
fmt.Printf("%s\n", opt.TakeOr("N/A"))
Output:
1
N/A

func MapWithError added in v0.1.0

func MapWithError[T, U any](option Option[T], mapper func(v T) (U, error)) (Option[U], error)

MapWithError converts given Option value to another Option value according to the mapper function that has the ability to return the value with an error. If given Option value is None, this returns (None, nil). Else if the mapper returns an error then this returns (None, error). Unless of them, i.e. given Option value is Some and the mapper doesn't return the error, this returns (Some[U], nil).

Example
mapperWithNoError := func(v int) (string, error) {
	return fmt.Sprintf("%d", v), nil
}

some := Some[int](1)
opt, err := MapWithError(some, mapperWithNoError)
fmt.Printf("err is nil: %v\n", err == nil)
fmt.Printf("%s\n", opt.TakeOr("N/A"))

none := None[int]()
opt, err = MapWithError(none, mapperWithNoError)
fmt.Printf("err is nil: %v\n", err == nil)
fmt.Printf("%s\n", opt.TakeOr("N/A"))

mapperWithError := func(v int) (string, error) {
	return "", errors.New("something wrong")
}
opt, err = MapWithError(some, mapperWithError)
fmt.Printf("err is nil: %v\n", err == nil)
fmt.Printf("%s\n", opt.TakeOr("N/A"))
Output:
err is nil: true
1
err is nil: true
N/A
err is nil: false
N/A

func None

func None[T any]() Option[T]

None is a function to make a Option type that doesn't have a value.

func Some

func Some[T any](value T) Option[T]

Some is a function to make a Option type instance with the actual value.

func Zip

func Zip[T, U any](opt1 Option[T], opt2 Option[U]) Option[Pair[T, U]]

Zip zips two Options into a Pair that has each Option's value. If either one of the Options is None, this also returns None.

Example
maybePair := Zip(Some[int](1), Some[string]("foo"))
pair, err := maybePair.Take()
fmt.Printf("is none => %v\n", maybePair.IsNone())
fmt.Printf("err is nil => %v\n", err == nil)
fmt.Printf("%d %s\n", pair.Value1, pair.Value2)

maybePair = Zip(Some[int](1), None[string]())
fmt.Printf("is none => %v\n", maybePair.IsNone())

maybePair = Zip(None[int](), Some[string]("foo"))
fmt.Printf("is none => %v\n", maybePair.IsNone())

maybePair = Zip(None[int](), None[string]())
fmt.Printf("is none => %v\n", maybePair.IsNone())
Output:
is none => false
err is nil => true
1 foo
is none => true
is none => true
is none => true

func ZipWith

func ZipWith[T, U, V any](opt1 Option[T], opt2 Option[U], zipper func(opt1 T, opt2 U) V) Option[V]

ZipWith zips two Options into a typed value according to the zipper function. If either one of the Options is None, this also returns None.

Example
type Data struct {
	A int
	B string
}

zipper := func(v1 int, v2 string) Data {
	return Data{
		A: v1,
		B: v2,
	}
}

maybeData := ZipWith(Some[int](1), Some[string]("foo"), zipper)
fmt.Printf("is none => %v\n", maybeData.IsNone())
d, err := maybeData.Take()
fmt.Printf("err is nil => %v\n", err == nil)
fmt.Printf("%d %s\n", d.A, d.B)

maybeData = ZipWith(Some[int](1), None[string](), zipper)
fmt.Printf("is none => %v\n", maybeData.IsNone())
maybeData = ZipWith(None[int](), Some[string]("foo"), zipper)
fmt.Printf("is none => %v\n", maybeData.IsNone())
maybeData = ZipWith(None[int](), None[string](), zipper)
fmt.Printf("is none => %v\n", maybeData.IsNone())
Output:
is none => false
err is nil => true
1 foo
is none => true
is none => true
is none => true

func (Option[T]) Filter

func (o Option[T]) Filter(predicate func(v T) bool) Option[T]

Filter returns self if the Option has a value and the value matches the condition of the predicate function. In other cases (i.e. it doesn't match with the predicate or the Option is None), this returns None value.

Example
isEven := func(v int) bool {
	return v%2 == 0
}

some := Some[int](2)
opt := some.Filter(isEven)
fmt.Printf("%d\n", opt.TakeOr(0))

some = Some[int](1)
opt = some.Filter(isEven)
fmt.Printf("%d\n", opt.TakeOr(0))

none := None[int]()
opt = none.Filter(isEven)
fmt.Printf("%d\n", opt.TakeOr(0))
Output:
2
0
0

func (Option[T]) IsNone

func (o Option[T]) IsNone() bool

IsNone returns whether the Option *doesn't* have a value or not.

Example
some := Some[int](1)
fmt.Printf("%v\n", some.IsNone())
none := None[int]()
fmt.Printf("%v\n", none.IsNone())
Output:
false
true

func (Option[T]) IsSome

func (o Option[T]) IsSome() bool

IsSome returns whether the Option has a value or not.

Example
some := Some[int](1)
fmt.Printf("%v\n", some.IsSome())
none := None[int]()
fmt.Printf("%v\n", none.IsSome())
Output:
true
false

func (Option[T]) Take

func (o Option[T]) Take() (T, error)

Take takes the contained value in Option. If Option value is Some, this returns the value that is contained in Option. On the other hand, this returns an ErrNoneValueTaken as the second return value.

Example
some := Some[int](1)
v, err := some.Take()
fmt.Printf("%d\n", v)
fmt.Printf("%v\n", err == nil)

none := None[int]()
_, err = none.Take()
fmt.Printf("%v\n", err == nil)
Output:
1
true
false

func (Option[T]) TakeOr

func (o Option[T]) TakeOr(fallbackValue T) T

TakeOr returns the actual value if the Option has a value. On the other hand, this returns fallbackValue.

Example
some := Some[int](1)
v := some.TakeOr(666)
fmt.Printf("%d\n", v)

none := None[int]()
v = none.TakeOr(666)
fmt.Printf("%d\n", v)
Output:
1
666

func (Option[T]) TakeOrElse

func (o Option[T]) TakeOrElse(fallbackFunc func() T) T

TakeOrElse returns the actual value if the Option has a value. On the other hand, this executes fallbackFunc and returns the result value of that function.

Example
some := Some[int](1)
v := some.TakeOrElse(func() int {
	return 666
})
fmt.Printf("%d\n", v)

none := None[int]()
v = none.TakeOrElse(func() int {
	return 666
})
fmt.Printf("%d\n", v)
Output:
1
666

type Pair

type Pair[T, U any] struct {
	Value1 T
	Value2 U
}

Pair is a data type that represents a tuple that has two elements.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL