Skip to content

Commit 1e748d5

Browse files
authored
feat: Create generic Option type inspired by Rust (#34)
1 parent b328603 commit 1e748d5

File tree

2 files changed

+132
-0
lines changed

2 files changed

+132
-0
lines changed

option.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package ldcommon
2+
3+
// Option represents an optional value: every Option is either Some and contains a value, or None, and does not.
4+
type Option[T any] struct {
5+
value T
6+
isDefined bool
7+
}
8+
9+
// Some creates an Option with a value.
10+
func Some[T any](value T) Option[T] {
11+
return Option[T]{value: value, isDefined: true}
12+
}
13+
14+
// None creates an Option with no value.
15+
func None[T any]() Option[T] {
16+
return Option[T]{isDefined: false}
17+
}
18+
19+
// IsSome returns true if the Option contains a value.
20+
func (o Option[T]) IsSome() bool {
21+
return o.isDefined
22+
}
23+
24+
// IsNone returns true if the Option does not contain a value.
25+
func (o Option[T]) IsNone() bool {
26+
return !o.isDefined
27+
}
28+
29+
// Unwrap returns the contained value, or panics if the Option is None.
30+
func (o Option[T]) Unwrap() T {
31+
if o.IsNone() {
32+
panic("called Unwrap on a None Option")
33+
}
34+
return o.value
35+
}
36+
37+
// UnwrapOr returns the contained value, or a provided default if the Option is None.
38+
func (o Option[T]) UnwrapOr(defaultValue T) T {
39+
if o.IsNone() {
40+
return defaultValue
41+
}
42+
return o.value
43+
}
44+
45+
// AsPtr returns a pointer to the contained value, or nil if the Option is None.
46+
func (o Option[T]) AsPtr() *T {
47+
if o.IsNone() {
48+
return nil
49+
}
50+
return &o.value
51+
}
52+
53+
// Map applies a function to the contained value (if any), and returns a new Option containing the result.
54+
func Map[T any, U any](o Option[T], f func(T) U) Option[U] {
55+
if o.IsNone() {
56+
return None[U]()
57+
}
58+
return Some(f(o.value))
59+
}
60+
61+
// OrElse returns the Option if it contains a value, or calls the provided function and returns its result otherwise.
62+
func (o Option[T]) OrElse(f func() Option[T]) Option[T] {
63+
if o.IsSome() {
64+
return o
65+
}
66+
return f()
67+
}

option_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package ldcommon
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func TestOptionSome(t *testing.T) {
11+
opt := Some(42)
12+
assert.True(t, opt.IsSome())
13+
assert.False(t, opt.IsNone())
14+
assert.Equal(t, 42, opt.Unwrap())
15+
}
16+
17+
func TestOptionNone(t *testing.T) {
18+
opt := None[int]()
19+
assert.False(t, opt.IsSome())
20+
assert.True(t, opt.IsNone())
21+
assert.Panics(t, func() { opt.Unwrap() })
22+
}
23+
24+
func TestOptionUnwrapOr(t *testing.T) {
25+
someOpt := Some(42)
26+
noneOpt := None[int]()
27+
28+
assert.Equal(t, 42, someOpt.UnwrapOr(100))
29+
assert.Equal(t, 100, noneOpt.UnwrapOr(100))
30+
}
31+
32+
func TestOptionMap(t *testing.T) {
33+
someOpt := Some(42)
34+
noneOpt := None[int]()
35+
36+
mappedSome := Map(someOpt, func(x int) string { return "Value: " + fmt.Sprint(x) })
37+
mappedNone := Map(noneOpt, func(x int) string { return "Value: " + fmt.Sprint(x) })
38+
39+
assert.True(t, mappedSome.IsSome())
40+
assert.False(t, mappedNone.IsSome())
41+
assert.Equal(t, "Value: 42", mappedSome.Unwrap())
42+
}
43+
44+
func TestOptionAsPtr(t *testing.T) {
45+
someOpt := Some(42)
46+
noneOpt := None[int]()
47+
48+
somePtr := someOpt.AsPtr()
49+
nonePtr := noneOpt.AsPtr()
50+
51+
assert.NotNil(t, somePtr)
52+
assert.Equal(t, 42, *somePtr)
53+
assert.Nil(t, nonePtr)
54+
}
55+
56+
func TestOptionOrElse(t *testing.T) {
57+
someOpt := Some(42)
58+
noneOpt := None[int]()
59+
60+
orElseSome := someOpt.OrElse(func() Option[int] { return Some(100) })
61+
orElseNone := noneOpt.OrElse(func() Option[int] { return Some(100) })
62+
63+
assert.Equal(t, 42, orElseSome.Unwrap())
64+
assert.Equal(t, 100, orElseNone.Unwrap())
65+
}

0 commit comments

Comments
 (0)