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 ¶
- func Contains[T comparable](val Value[T], v T) bool
- func UnzipWith[T, T2, T3 any](val Value[T], f func(T) (T2, T3)) (val2 Value[T2], val3 Value[T3])
- type Value
- func FlatMap[T, T2 any](val Value[T], f func(T) Value[T2]) Value[T2]
- func Flatten[T any](val Value[Value[T]]) Value[T]
- func Map[T, T2 any](val Value[T], f func(T) T2) Value[T2]
- func Of[T any](v T, ok bool) Value[T]
- func OfAssert[T, Tx any](x Tx) Value[T]
- func OfIndex[K comparable, V any, M ~map[K]V](m M, k K) Value[V]
- func OfNotOk[T any]() Value[T]
- func OfOk[T any](v T) Value[T]
- func OfPointer[T any](p *T) Value[*T]
- func OfReceive[T any](ch <-chan T) Value[T]
- func ZipWith[T, T2, T3 any](val Value[T], val2 Value[T2], f func(T, T2) T3) Value[T3]
- func (val Value[T]) Do(f func(T)) Value[T]
- func (val Value[T]) Filter(f func(T) bool) Value[T]
- func (val Value[T]) IsOk() bool
- func (val Value[T]) MarshalJSON() ([]byte, error)
- func (val Value[T]) MustOk() T
- func (val Value[T]) OfOk() Value[T]
- func (val Value[T]) Ok(dst *T) bool
- func (val Value[T]) Or(def T) T
- func (val Value[T]) OrElse(f func() T) T
- func (val Value[T]) OrZero() T
- func (val *Value[T]) UnmarshalJSON(data []byte) error
- func (val Value[T]) Unpack() (T, bool)
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 ¶
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 ¶
FlatMap returns the result of f on the underlying value. Returns a not-ok Value if val is not ok.
func Flatten ¶
Flatten returns the underlying Value of val. Returns a not-ok Value if val is not ok.
func Map ¶
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 ¶
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
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 ¶
OfNotOk creates a Value that is not ok. This aids in comparisons, enabling the use of Value in switch statements.
func OfPointer ¶ added in v0.7.0
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
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 ¶
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]) Filter ¶
Filter returns val if f returns true for the underlying value. Otherwise returns a not-ok Value.
func (Value[T]) MarshalJSON ¶ added in v0.8.0
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 ¶
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 ¶
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
UnmarshalJSON decodes data into val. val will be ok if the underlying value was unmarshaled successfully. Does nothing if data is the literal null.