optional

package
v0.11.1 Latest Latest
Warning

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

Go to latest
Published: Oct 19, 2022 License: MIT Imports: 1 Imported by: 3

Documentation

Overview

Package optional provides a type that optionally contains a value.

Example
package main

import (
	"fmt"
	"strconv"

	"github.com/phelmkamp/valor/optional"
)

func main() {
	m := map[string]int{"foo": 42}
	val := optional.OfIndex(m, "foo")
	fmt.Println(val.IsOk()) // true

	var foo int
	fmt.Println(val.Ok(&foo), foo) // true 42

	valStr := optional.Map(val, strconv.Itoa)
	fmt.Println(valStr) // {42 true}

	val = optional.OfIndex(m, "bar")
	fmt.Println(val.Or(-1))                          // -1
	fmt.Println(val.OrZero())                        // 0
	fmt.Println(val.OrElse(func() int { return 1 })) // 1

	// switch
	switch val {
	case val.OfOk():
		foo = val.MustOk()
		fmt.Println(foo)
	case optional.OfNotOk[int]():
		fmt.Println("Not Ok")
		return
	}
}
Output:

true
true 42
{42 true}
-1
0
1
Not Ok
Example (Channel)

Example_channel demonstrates that a custom channel type can be implemented that forces consumers to handle a closed channel.

ch := Chan[int]{ch: make(chan int, 1)}
ch.ch <- 0
fmt.Println(ch.Receive())
ch.Close()
fmt.Println(ch.Receive())
Output:

{0 true}
{0 false}
Example (Json)

Example_json demonstrates that a Value can be marshaled to and unmarshaled from JSON.

package main

import (
	"encoding/json"
	"fmt"
	"log"

	"github.com/phelmkamp/valor/optional"
)

func main() {
	type Obj struct {
		Name string              `json:"name"`
		Val  optional.Value[int] `json:"val"`
	}
	b, err := json.Marshal(Obj{Name: "foo", Val: optional.OfOk(0)})
	if err != nil {
		log.Fatalf("json.Marshal() failed: %v", err)
	}
	fmt.Println(string(b))
	var obj Obj
	err = json.Unmarshal(b, &obj)
	if err != nil {
		log.Fatalf("json.Unmarshal() failed: %v", err)
	}
	fmt.Println(obj)
	fmt.Println()

	b, err = json.Marshal(Obj{Name: "foo", Val: optional.OfNotOk[int]()})
	if err != nil {
		log.Fatalf("json.Marshal() failed: %v", err)
	}
	fmt.Println(string(b))
	obj = Obj{}
	err = json.Unmarshal(b, &obj)
	if err != nil {
		log.Fatalf("json.Unmarshal() failed: %v", err)
	}
	fmt.Println(obj)
}
Output:

{"name":"foo","val":0}
{foo {0 true}}

{"name":"foo","val":null}
{foo {0 false}}
Example (Map)

Example_map demonstrates that a custom map type can be implemented that forces consumers to handle a missing pair.

m := Map[string, int]{m: map[string]int{"foo": 0}}
fmt.Println(m.Index("foo"))
fmt.Println(m.Index("bar"))
Output:

{0 true}
{0 false}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Contains

func Contains[T comparable](val Value[T], v T) bool

Contains returns whether the underlying value equals v. Returns false if val is not ok.

func UnzipWith

func UnzipWith[T, T2, T3 any](val Value[T], f func(T) (T2, T3)) (val2 Value[T2], val3 Value[T3])

UnzipWith calls f with the underlying value of val and returns Values of the result. Does nothing and returns not-ok Values if val is not ok.

Example
package main

import (
	"fmt"
	"strings"

	"github.com/phelmkamp/valor/optional"
)

func splitFirstColon(s string) (string, int) {
	i := strings.Index(s, ":")
	if i < 0 {
		return s, i
	}
	return s[:i], i
}

func main() {
	str := "foo:bar:baz"
	for {
		strVal, idxVal := optional.UnzipWith(optional.OfOk(str), splitFirstColon)
		fmt.Print(strVal.MustOk())
		idxVal = optional.FlatMap(idxVal, func(i int) optional.Value[int] { return optional.Of(i, i >= 0) })
		if !idxVal.IsOk() {
			break
		}
		i := idxVal.MustOk()
		str = str[i+1:]
		fmt.Println(" " + str)
	}
}
Output:

foo bar:baz
bar baz
baz
Example (Tuple)
package main

import (
	"fmt"

	"github.com/phelmkamp/valor/optional"
	"github.com/phelmkamp/valor/tuple/four"
	"github.com/phelmkamp/valor/tuple/singleton"
	"github.com/phelmkamp/valor/tuple/two"
)

func main() {
	v1234 := optional.OfOk(four.TupleOf(1, "two", 3.0, []int{4}))
	v13, v24 := optional.UnzipWith(v1234, two.TupleUnzip[int, string, float64, []int])
	fmt.Println(v13.MustOk(), v24.MustOk())
	v1, v3 := optional.UnzipWith(v13, singleton.SetUnzip[int, float64])
	v2, v4 := optional.UnzipWith(v24, singleton.SetUnzip[string, []int])
	fmt.Println(v1.MustOk(), v3.MustOk(), v2.MustOk(), v4.MustOk())
}
Output:

{1 3} {two [4]}
{1} {3} {two} {[4]}

Types

type Value

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

Value either contains a value (ok) or nothing (not ok).

func FlatMap

func FlatMap[T, T2 any](val Value[T], f func(T) Value[T2]) Value[T2]

FlatMap returns the result of f on the underlying value. Returns a not-ok Value if val is not ok.

func Flatten

func Flatten[T any](val Value[Value[T]]) Value[T]

Flatten returns the underlying Value of val. Returns a not-ok Value if val is not ok.

func Map

func Map[T, T2 any](val Value[T], f func(T) T2) Value[T2]

Map returns a Value of the result of f on the underlying value. Returns a not-ok Value if val is not ok.

func Of

func Of[T any](v T, ok bool) Value[T]

Of creates a Value of v if ok is true. This aids interoperability with return values that follow the "comma ok" idiom.

func OfAssert added in v0.7.0

func OfAssert[T, Tx any](x Tx) Value[T]

OfAssert performs the type assertion x.(T) and creates a Value of the result. Returns a not-ok Value if the type assertion fails.

func OfIndex added in v0.7.0

func OfIndex[K comparable, V any, M ~map[K]V](m M, k K) Value[V]

OfIndex performs the map index m[k] and creates a Value of the result. Returns a not-ok Value if k is not present in the map.

func OfNotOk

func OfNotOk[T any]() Value[T]

OfNotOk creates a Value that is not ok. This aids in comparisons, enabling the use of Value in switch statements.

func OfOk

func OfOk[T any](v T) Value[T]

OfOk creates an ok Value of v.

func OfPointer added in v0.7.0

func OfPointer[T any](p *T) Value[*T]

OfPointer creates a Value of the pointer p. Returns a not-ok Value if p is nil.

Example

ExampleOfPointer demonstrates how to dereference a pointer without the risk of a panic due to nil.

package main

import (
	"fmt"

	"github.com/phelmkamp/valor/optional"
)

func main() {
	var i *int
	j := optional.Map(
		optional.OfPointer(i),
		func(p *int) int { return *p },
	).OrZero()
	fmt.Println(j)

	i = new(int)
	*i++
	j = optional.Map(
		optional.OfPointer(i),
		func(p *int) int { return *p },
	).OrZero()
	fmt.Println(j)
}
Output:

0
1

func OfReceive added in v0.7.0

func OfReceive[T any](ch <-chan T) Value[T]

OfReceive performs a blocking receive on ch and creates a Value of the result. Returns a not-ok Value if ch is nil or closed.

func ZipWith

func ZipWith[T, T2, T3 any](val Value[T], val2 Value[T2], f func(T, T2) T3) Value[T3]

ZipWith calls f with the underlying values of val and val2 and returns a Value of the result. Returns a not-ok Value if either val or val2 is not ok.

Example (Tuple)
package main

import (
	"fmt"

	"github.com/phelmkamp/valor/optional"
	"github.com/phelmkamp/valor/tuple/singleton"
	"github.com/phelmkamp/valor/tuple/two"
)

func main() {
	v1 := optional.OfOk(singleton.SetOf(1))
	v2 := optional.OfOk(singleton.SetOf("two"))
	v3 := optional.OfOk(singleton.SetOf(3.0))
	v4 := optional.OfOk(singleton.SetOf([]int{4}))
	v12 := optional.ZipWith(v1, v2, singleton.SetZip[int, string])
	v34 := optional.ZipWith(v3, v4, singleton.SetZip[float64, []int])
	fmt.Println(v12.MustOk(), v34.MustOk())
	v1324 := optional.ZipWith(v12, v34, two.TupleZip[int, float64, string, []int])
	fmt.Println(v1324.MustOk())
}
Output:

{1 two} {3 [4]}
{1 3 two [4]}

func (Value[T]) Do

func (val Value[T]) Do(f func(T)) Value[T]

Do calls f with the underlying value if ok. Does nothing if not ok.

func (Value[T]) Filter

func (val Value[T]) Filter(f func(T) bool) Value[T]

Filter returns val if f returns true for the underlying value. Otherwise returns a not-ok Value.

func (Value[T]) IsOk

func (val Value[T]) IsOk() bool

IsOk returns whether v contains a value.

func (Value[T]) MarshalJSON added in v0.8.0

func (val Value[T]) MarshalJSON() ([]byte, error)

MarshalJSON encodes val as JSON. Marshals the underlying value if ok, the literal null if not ok.

func (Value[T]) MustOk

func (val Value[T]) MustOk() T

MustOk is like Ok but panics if not ok. This simplifies access to the underlying value in cases where it's known that val is ok.

func (Value[T]) OfOk

func (val Value[T]) OfOk() Value[T]

OfOk creates an ok Value of the underlying value. This aids in comparisons, enabling the use of val in switch statements.

func (Value[T]) Ok

func (val Value[T]) Ok(dst *T) bool

Ok sets dst to the underlying value if ok. Returns true if ok, false if not ok.

func (Value[T]) Or

func (val Value[T]) Or(def T) T

Or returns the underlying value if ok, or def if not ok.

func (Value[T]) OrElse

func (val Value[T]) OrElse(f func() T) T

OrElse returns the underlying value if ok, or the result of f if not ok.

Example

ExampleValue_OrElse demonstrates that OrElse can be used to work with a cache.

package main

import (
	"fmt"

	"github.com/phelmkamp/valor/optional"
)

func main() {
	cache := make(map[string]string)
	load := func(k string) string {
		// expensive call to load value goes here
		v := "bar"
		cache[k] = v
		return v
	}

	v := optional.OfIndex(cache, "foo").OrElse(func() string { return load("foo") })
	fmt.Println(v)
}
Output:

bar

func (Value[T]) OrZero

func (val Value[T]) OrZero() T

OrZero returns the underlying value if ok, or the zero value if not ok.

func (*Value[T]) UnmarshalJSON added in v0.8.0

func (val *Value[T]) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes data into val. val will be ok if the underlying value was unmarshaled successfully. Does nothing if data is the literal null.

func (Value[T]) Unpack added in v0.9.0

func (val Value[T]) Unpack() (T, bool)

Unpack returns the underlying value and whether it is ok. This aids in assigning to variables or function arguments.

Jump to

Keyboard shortcuts

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