ohhhhh
parent
301da04f9b
commit
b3ee3e6a2d
@ -0,0 +1,46 @@
|
||||
package opt
|
||||
|
||||
// Val is an optional value
|
||||
type Val[T any] struct {
|
||||
val T
|
||||
ok bool
|
||||
}
|
||||
|
||||
// New creates an optional value
|
||||
func New[T any](v T, ok bool) Val[T] {
|
||||
if ok {
|
||||
return Some(v)
|
||||
}
|
||||
return None[T]()
|
||||
}
|
||||
|
||||
// None creates an empty optional value
|
||||
func None[T any]() Val[T] { return Val[T]{} }
|
||||
|
||||
// NoneOf is the same as none, but it takes a parameter that it throws away.
|
||||
// This allows the type T to be inferred.
|
||||
func NoneOf[T any](v T) Val[T] { return Val[T]{} }
|
||||
|
||||
// Some creates a filled optional value
|
||||
func Some[T any](v T) Val[T] {
|
||||
return Val[T]{
|
||||
val: v,
|
||||
ok: true,
|
||||
}
|
||||
}
|
||||
|
||||
// Open retrives the contents of our optional value
|
||||
func (v Val[T]) Open() (T, bool) {
|
||||
return v.val, v.ok
|
||||
}
|
||||
|
||||
// Bind takes a function that doesn't understand optionals and gives you
|
||||
// another function that does
|
||||
func Bind[X, Y any](f func(X) Y) func(Val[X]) Val[Y] {
|
||||
return func(mx Val[X]) Val[Y] {
|
||||
if x, ok := mx.Open(); ok {
|
||||
return Some(f(x))
|
||||
}
|
||||
return None[Y]()
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package opt
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
func TestNone(t *testing.T) {
|
||||
s := None[string]()
|
||||
if s.ok {
|
||||
t.Error("should not be ok")
|
||||
}
|
||||
if _, ok := s.Open(); ok {
|
||||
t.Error("should not be ok")
|
||||
}
|
||||
|
||||
s2 := NoneOf("poop")
|
||||
if s2.ok {
|
||||
t.Error("should not be ok")
|
||||
}
|
||||
if _, ok := s2.Open(); ok {
|
||||
t.Error("should not be ok")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSome(t *testing.T) {
|
||||
s := Some("poop")
|
||||
if !s.ok {
|
||||
t.Error("should be ok")
|
||||
}
|
||||
|
||||
v, ok := s.Open()
|
||||
if !ok {
|
||||
t.Fatal("should be ok")
|
||||
}
|
||||
|
||||
if v != "poop" {
|
||||
t.Error("should be poop")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBind(t *testing.T) {
|
||||
count := Bind(utf8.RuneCountInString)
|
||||
|
||||
t.Run("bind some", func(t *testing.T) {
|
||||
m := count(Some("poop"))
|
||||
|
||||
n, ok := m.Open()
|
||||
if !ok {
|
||||
t.Fatal("should be ok")
|
||||
}
|
||||
if n != 4 {
|
||||
t.Errorf("wanted 4 but got %d instead", n)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("bind non", func(t *testing.T) {
|
||||
m := count(None[string]())
|
||||
|
||||
n, ok := m.Open()
|
||||
if ok {
|
||||
t.Fatal("should not be ok")
|
||||
}
|
||||
if n != 0 {
|
||||
t.Errorf("wanted 0 but got %d instead", n)
|
||||
}
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue