Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Add optional.ExtractValue() to be able to handle Option type within interface{} value #29794

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions modules/optional/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

package optional

import "reflect"

type Option[T any] []T

func None[T any]() Option[T] {
Expand Down Expand Up @@ -43,3 +45,29 @@ func (o Option[T]) ValueOrDefault(v T) T {
}
return v
}

// ExcractValue return value or nil and bool if object was an Optional
// it should only be used if you already have to deal with interface{} values
// and expect an Option type within it.
func ExcractValue(obj any) (any, bool) {
rt := reflect.TypeOf(obj)
if rt.Kind() != reflect.Slice {
return nil, false
}

type hasHasFunc interface {
Has() bool
}
if hasObj, ok := obj.(hasHasFunc); !ok {
return nil, false
} else if !hasObj.Has() {
return nil, true
}

rv := reflect.ValueOf(obj)
if rv.Len() != 1 {
// it's still false as optional.Option[T] types would have reported with hasObj.Has() that it is empty
return nil, false
}
return rv.Index(0).Interface(), true
}
43 changes: 43 additions & 0 deletions modules/optional/option_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,46 @@
assert.True(t, opt3.Has())
assert.Equal(t, int(1), opt3.Value())
}

func TestExcractValue(t *testing.T) {
val, ok := optional.ExcractValue("aaaa")
assert.False(t, ok)
assert.Nil(t, val)

val, ok = optional.ExcractValue(optional.Some("aaaa"))
assert.True(t, ok)
if assert.NotNil(t, val) {
val, ok := val.(string)
assert.True(t, ok)
assert.EqualValues(t, "aaaa", val)
}

val, ok = optional.ExcractValue(optional.None[float64]())
assert.True(t, ok)
assert.Nil(t, val)

val, ok = optional.ExcractValue(&fakeHas{})
assert.False(t, ok)
assert.Nil(t, val)

wrongType := make(fakeHas2, 0, 1)
val, ok = optional.ExcractValue(wrongType)
assert.False(t, ok)
assert.Nil(t, val)
}

func toPtr[T any](val T) *T {

Check failure on line 88 in modules/optional/option_test.go

View workflow job for this annotation

GitHub Actions / lint-backend

func `toPtr` is unused (unused)

Check failure on line 88 in modules/optional/option_test.go

View workflow job for this annotation

GitHub Actions / lint-go-gogit

func `toPtr` is unused (unused)

Check failure on line 88 in modules/optional/option_test.go

View workflow job for this annotation

GitHub Actions / lint-go-windows

func `toPtr` is unused (unused)
return &val
}

type fakeHas struct{}

func (fakeHas) Has() bool {
return true
}

type fakeHas2 []string

func (fakeHas2) Has() bool {
return true
}
Loading