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