github.com/moznion/go-optional@v0.11.1-0.20240312043125-6881072e44c1/option.go (about) 1 package optional 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "fmt" 8 ) 9 10 var ( 11 // ErrNoneValueTaken represents the error that is raised when None value is taken. 12 ErrNoneValueTaken = errors.New("none value taken") 13 ) 14 15 // Option is a data type that must be Some (i.e. having a value) or None (i.e. doesn't have a value). 16 // This type implements database/sql/driver.Valuer and database/sql.Scanner. 17 type Option[T any] []T 18 19 const ( 20 value = iota 21 ) 22 23 // Some is a function to make an Option type value with the actual value. 24 func Some[T any](v T) Option[T] { 25 return Option[T]{ 26 value: v, 27 } 28 } 29 30 // None is a function to make an Option type value that doesn't have a value. 31 func None[T any]() Option[T] { 32 return nil 33 } 34 35 // FromNillable is a function to make an Option type value with the nillable value with value de-referencing. 36 // If the given value is not nil, this returns Some[T] value. On the other hand, if the value is nil, this returns None[T]. 37 // This function does "dereference" for the value on packing that into Option value. If this value is not preferable, please consider using PtrFromNillable() instead. 38 func FromNillable[T any](v *T) Option[T] { 39 if v == nil { 40 return None[T]() 41 } 42 return Some[T](*v) 43 } 44 45 // PtrFromNillable is a function to make an Option type value with the nillable value without value de-referencing. 46 // If the given value is not nil, this returns Some[*T] value. On the other hand, if the value is nil, this returns None[*T]. 47 // This function doesn't "dereference" the value on packing that into the Option value; in other words, this puts the as-is pointer value into the Option envelope. 48 // This behavior contrasts with the FromNillable() function's one. 49 func PtrFromNillable[T any](v *T) Option[*T] { 50 if v == nil { 51 return None[*T]() 52 } 53 return Some[*T](v) 54 } 55 56 // IsNone returns whether the Option *doesn't* have a value or not. 57 func (o Option[T]) IsNone() bool { 58 return o == nil 59 } 60 61 // IsSome returns whether the Option has a value or not. 62 func (o Option[T]) IsSome() bool { 63 return o != nil 64 } 65 66 // Unwrap returns the value regardless of Some/None status. 67 // If the Option value is Some, this method returns the actual value. 68 // On the other hand, if the Option value is None, this method returns the *default* value according to the type. 69 func (o Option[T]) Unwrap() T { 70 if o.IsNone() { 71 var defaultValue T 72 return defaultValue 73 } 74 return o[value] 75 } 76 77 // UnwrapAsPtr returns the contained value in receiver Option as a pointer. 78 // This is similar to `Unwrap()` method but the difference is this method returns a pointer value instead of the actual value. 79 // If the receiver Option value is None, this method returns nil. 80 func (o Option[T]) UnwrapAsPtr() *T { 81 if o.IsNone() { 82 return nil 83 } 84 return &o[value] 85 } 86 87 // Take takes the contained value in Option. 88 // If Option value is Some, this returns the value that is contained in Option. 89 // On the other hand, this returns an ErrNoneValueTaken as the second return value. 90 func (o Option[T]) Take() (T, error) { 91 if o.IsNone() { 92 var defaultValue T 93 return defaultValue, ErrNoneValueTaken 94 } 95 return o[value], nil 96 } 97 98 // TakeOr returns the actual value if the Option has a value. 99 // On the other hand, this returns fallbackValue. 100 func (o Option[T]) TakeOr(fallbackValue T) T { 101 if o.IsNone() { 102 return fallbackValue 103 } 104 return o[value] 105 } 106 107 // TakeOrElse returns the actual value if the Option has a value. 108 // On the other hand, this executes fallbackFunc and returns the result value of that function. 109 func (o Option[T]) TakeOrElse(fallbackFunc func() T) T { 110 if o.IsNone() { 111 return fallbackFunc() 112 } 113 return o[value] 114 } 115 116 // Or returns the Option value according to the actual value existence. 117 // If the receiver's Option value is Some, this function pass-through that to return. Otherwise, this value returns the `fallbackOptionValue`. 118 func (o Option[T]) Or(fallbackOptionValue Option[T]) Option[T] { 119 if o.IsNone() { 120 return fallbackOptionValue 121 } 122 return o 123 } 124 125 // OrElse returns the Option value according to the actual value existence. 126 // If the receiver's Option value is Some, this function pass-through that to return. Otherwise, this executes `fallbackOptionFunc` and returns the result value of that function. 127 func (o Option[T]) OrElse(fallbackOptionFunc func() Option[T]) Option[T] { 128 if o.IsNone() { 129 return fallbackOptionFunc() 130 } 131 return o 132 } 133 134 // Filter returns self if the Option has a value and the value matches the condition of the predicate function. 135 // In other cases (i.e. it doesn't match with the predicate or the Option is None), this returns None value. 136 func (o Option[T]) Filter(predicate func(v T) bool) Option[T] { 137 if o.IsNone() || !predicate(o[value]) { 138 return None[T]() 139 } 140 return o 141 } 142 143 // IfSome calls given function with the value of Option if the receiver value is Some. 144 func (o Option[T]) IfSome(f func(v T)) { 145 if o.IsNone() { 146 return 147 } 148 f(o[value]) 149 } 150 151 // IfSomeWithError calls given function with the value of Option if the receiver value is Some. 152 // This method propagates the error of given function, and if the receiver value is None, this returns nil error. 153 func (o Option[T]) IfSomeWithError(f func(v T) error) error { 154 if o.IsNone() { 155 return nil 156 } 157 return f(o[value]) 158 } 159 160 // IfNone calls given function if the receiver value is None. 161 func (o Option[T]) IfNone(f func()) { 162 if o.IsSome() { 163 return 164 } 165 f() 166 } 167 168 // IfNoneWithError calls given function if the receiver value is None. 169 // This method propagates the error of given function, and if the receiver value is Some, this returns nil error. 170 func (o Option[T]) IfNoneWithError(f func() error) error { 171 if o.IsSome() { 172 return nil 173 } 174 return f() 175 } 176 177 func (o Option[T]) String() string { 178 if o.IsNone() { 179 return "None[]" 180 } 181 182 v := o.Unwrap() 183 if stringer, ok := interface{}(v).(fmt.Stringer); ok { 184 return fmt.Sprintf("Some[%s]", stringer) 185 } 186 return fmt.Sprintf("Some[%v]", v) 187 } 188 189 // Map converts given Option value to another Option value according to the mapper function. 190 // If given Option value is None, this also returns None. 191 func Map[T, U any](option Option[T], mapper func(v T) U) Option[U] { 192 if option.IsNone() { 193 return None[U]() 194 } 195 196 return Some(mapper(option[value])) 197 } 198 199 // MapOr converts given Option value to another *actual* value according to the mapper function. 200 // If given Option value is None, this returns fallbackValue. 201 func MapOr[T, U any](option Option[T], fallbackValue U, mapper func(v T) U) U { 202 if option.IsNone() { 203 return fallbackValue 204 } 205 return mapper(option[value]) 206 } 207 208 // 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. 209 // If given Option value is None, this returns (None, nil). Else if the mapper returns an error then this returns (None, error). 210 // Unless of them, i.e. given Option value is Some and the mapper doesn't return the error, this returns (Some[U], nil). 211 func MapWithError[T, U any](option Option[T], mapper func(v T) (U, error)) (Option[U], error) { 212 if option.IsNone() { 213 return None[U](), nil 214 } 215 216 u, err := mapper(option[value]) 217 if err != nil { 218 return None[U](), err 219 } 220 return Some(u), nil 221 } 222 223 // 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. 224 // If given Option value is None, this returns (fallbackValue, nil). Else if the mapper returns an error then returns (_, error). 225 // Unless of them, i.e. given Option value is Some and the mapper doesn't return the error, this returns (U, nil). 226 func MapOrWithError[T, U any](option Option[T], fallbackValue U, mapper func(v T) (U, error)) (U, error) { 227 if option.IsNone() { 228 return fallbackValue, nil 229 } 230 return mapper(option[value]) 231 } 232 233 // FlatMap converts give Option value to another Option value according to the mapper function. 234 // The difference from the Map is the mapper function returns an Option value instead of the bare value. 235 // If given Option value is None, this also returns None. 236 func FlatMap[T, U any](option Option[T], mapper func(v T) Option[U]) Option[U] { 237 if option.IsNone() { 238 return None[U]() 239 } 240 241 return mapper(option[value]) 242 } 243 244 // FlatMapOr converts given Option value to another *actual* value according to the mapper function. 245 // The difference from the MapOr is the mapper function returns an Option value instead of the bare value. 246 // If given Option value is None or mapper function returns None, this returns fallbackValue. 247 func FlatMapOr[T, U any](option Option[T], fallbackValue U, mapper func(v T) Option[U]) U { 248 if option.IsNone() { 249 return fallbackValue 250 } 251 252 return (mapper(option[value])).TakeOr(fallbackValue) 253 } 254 255 // FlatMapWithError converts given Option value to another Option value according to the mapper function that has the ability to return the value with an error. 256 // The difference from the MapWithError is the mapper function returns an Option value instead of the bare value. 257 // If given Option value is None, this returns (None, nil). Else if the mapper returns an error then this returns (None, error). 258 // Unless of them, i.e. given Option value is Some and the mapper doesn't return the error, this returns (Some[U], nil). 259 func FlatMapWithError[T, U any](option Option[T], mapper func(v T) (Option[U], error)) (Option[U], error) { 260 if option.IsNone() { 261 return None[U](), nil 262 } 263 264 mapped, err := mapper(option[value]) 265 if err != nil { 266 return None[U](), err 267 } 268 return mapped, nil 269 } 270 271 // FlatMapOrWithError converts given Option value to another *actual* value according to the mapper function that has the ability to return the value with an error. 272 // The difference from the MapOrWithError is the mapper function returns an Option value instead of the bare value. 273 // If given Option value is None, this returns (fallbackValue, nil). Else if the mapper returns an error then returns ($zero_value_of_type, error). 274 // Unless of them, i.e. given Option value is Some and the mapper doesn't return the error, this returns (U, nil). 275 func FlatMapOrWithError[T, U any](option Option[T], fallbackValue U, mapper func(v T) (Option[U], error)) (U, error) { 276 if option.IsNone() { 277 return fallbackValue, nil 278 } 279 280 maybe, err := mapper(option[value]) 281 if err != nil { 282 var zeroValue U 283 return zeroValue, err 284 } 285 286 return maybe.TakeOr(fallbackValue), nil 287 } 288 289 // Pair is a data type that represents a tuple that has two elements. 290 type Pair[T, U any] struct { 291 Value1 T 292 Value2 U 293 } 294 295 // Zip zips two Options into a Pair that has each Option's value. 296 // If either one of the Options is None, this also returns None. 297 func Zip[T, U any](opt1 Option[T], opt2 Option[U]) Option[Pair[T, U]] { 298 if opt1.IsSome() && opt2.IsSome() { 299 return Some(Pair[T, U]{ 300 Value1: opt1[value], 301 Value2: opt2[value], 302 }) 303 } 304 305 return None[Pair[T, U]]() 306 } 307 308 // ZipWith zips two Options into a typed value according to the zipper function. 309 // If either one of the Options is None, this also returns None. 310 func ZipWith[T, U, V any](opt1 Option[T], opt2 Option[U], zipper func(opt1 T, opt2 U) V) Option[V] { 311 if opt1.IsSome() && opt2.IsSome() { 312 return Some(zipper(opt1[value], opt2[value])) 313 } 314 return None[V]() 315 } 316 317 // Unzip extracts the values from a Pair and pack them into each Option value. 318 // If the given zipped value is None, this returns None for all return values. 319 func Unzip[T, U any](zipped Option[Pair[T, U]]) (Option[T], Option[U]) { 320 if zipped.IsNone() { 321 return None[T](), None[U]() 322 } 323 324 pair := zipped[value] 325 return Some(pair.Value1), Some(pair.Value2) 326 } 327 328 // UnzipWith extracts the values from the given value according to the unzipper function and pack the into each Option value. 329 // If the given zipped value is None, this returns None for all return values. 330 func UnzipWith[T, U, V any](zipped Option[V], unzipper func(zipped V) (T, U)) (Option[T], Option[U]) { 331 if zipped.IsNone() { 332 return None[T](), None[U]() 333 } 334 335 v1, v2 := unzipper(zipped[value]) 336 return Some(v1), Some(v2) 337 } 338 339 var jsonNull = []byte("null") 340 341 func (o Option[T]) MarshalJSON() ([]byte, error) { 342 if o.IsNone() { 343 return jsonNull, nil 344 } 345 346 marshal, err := json.Marshal(o.Unwrap()) 347 if err != nil { 348 return nil, err 349 } 350 return marshal, nil 351 } 352 353 func (o *Option[T]) UnmarshalJSON(data []byte) error { 354 if len(data) <= 0 || bytes.Equal(data, jsonNull) { 355 *o = None[T]() 356 return nil 357 } 358 359 var v T 360 err := json.Unmarshal(data, &v) 361 if err != nil { 362 return err 363 } 364 *o = Some(v) 365 366 return nil 367 }