-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathoptional.go
135 lines (111 loc) · 3.5 KB
/
optional.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package fuego
import (
"reflect"
)
// Optional is a container object which may or may not contain a value (NO: nil is considered a non-value).
// See IsPresent().
//
// Additional methods that depend on the presence or absence of a contained value are provided,
// such as OrElse() (returns a default value if no value is present) and IfPresent()
// (performs an action if a value is present).
//
// This is a value-based class; programmers should treat instances that are equal as interchangeable.
type Optional[T any] struct {
value T
present bool
}
// IsPresent return true if a value is present.
// If no value is present, the object is considered empty and IsPresent() returns false.
func (o Optional[T]) IsPresent() bool {
return o.present
}
// Filter returns an Optional describing the value if a value is present, and the value matches the
// given predicate, otherwise returns an empty Optional.
func (o Optional[T]) Filter(p Predicate[T]) Optional[T] {
if o.present && p(o.value) {
return o
}
return OptionalEmpty[T]()
}
// IfPresent performs the given action with the value, if a value is present,
// otherwise performs the given empty-based action.
func (o Optional[T]) IfPresent(c Consumer[T]) {
if o.present {
c(o.value)
}
}
// Get returns the value if present, otherwise panics.
func (o Optional[T]) Get() T {
if o.present {
return o.value
}
panic(PanicNoSuchElement)
}
// Or returns an Optional describing the value if present, otherwise returns an Optional produced by the
// supplying function.
func (o Optional[T]) Or(s Supplier[Optional[T]]) Optional[T] {
if o.present {
return o
}
return s()
}
// OrElse returns the value if present, otherwise returns other.
func (o Optional[T]) OrElse(other T) T {
if o.present {
return o.value
}
return other
}
// OrElseGet returns the value if present, otherwise returns the result produced by the supplying function.
func (o Optional[T]) OrElseGet(other Supplier[T]) T {
if o.present {
return o.value
}
return other()
}
// FlatMap returns the result of applying the given Optional-bearing mapping function to the value if
// present, otherwise returns an empty Optional.
func (o Optional[T]) FlatMap(f Function[T, Optional[Any]]) Optional[Any] {
if o.present {
return f(o.value)
}
return OptionalEmpty[Any]()
}
// Map returns an Optional describing (as if by ofNullable(T)) the result of applying the given mapping
// function to the value if present, otherwise returns an empty Optional.
// If the mapping function returns a nil result then this method returns an empty Optional.
func (o Optional[T]) Map(f Function[T, Any]) Optional[Any] {
if o.present {
val := f(o.value)
if val == nil {
return OptionalEmpty[Any]()
}
return OptionalOf(val)
}
return OptionalEmpty[Any]()
}
// OptionalOf returns an Optional describing the given (NO: non-nil) value.
// Currently, Go 1.18 does not permit nil generic types.
// See: https://github.com/golang/go/issues/22729
func OptionalOf[T any](val T) Optional[T] {
return Optional[T]{
value: val,
present: !isNil(val),
}
}
func isNil(v any) bool {
// hat tip to TeaEntityLab/fpGo:
// https://github.com/TeaEntityLab/fpGo/blob/5a35fcbc23e384be5f9b33069e3e3ecc9c661bf4/fp.go#L1218
val := reflect.ValueOf(v)
kind := reflect.ValueOf(v).Kind()
if kind == reflect.Ptr {
return val.IsNil()
}
return !val.IsValid()
}
// OptionalEmpty returns an empty Optional instance. No value is present for this Optional.
func OptionalEmpty[T any]() Optional[T] {
return Optional[T]{
present: false,
}
}