options

package module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 5, 2024 License: MIT Imports: 9 Imported by: 0

README

options

cybozu-go/options provides Option[T], which represents an optional value of type T.

Example

opt := options.New(42) // or option.None[int]()

fmt.Println(opt) // prints "42"
fmt.Printf("%#v\n", opt) // prints "options.New(42)"

if opt.IsPresent() {
	// opt.Unwrap panics when opt is None.
	// When there are feasible default values, you can use UnwrapOr or UnwrapOrZero, which do not panic.
	v := opt.Unwrap()
	DoSomething(v)
}

// You can also use Unpack to check presence and get the value at once.
if v, ok := opt.Unpack(); ok {
	DoSomething(v)
}

Interoperability

  • Option[T] can be serialized into or deserialized from JSON by encoding/json.
    • An Option[T] is serialized as if it is *T.
  • Option[T] can be inserted into or selected from databases by database/sql.
    • Option[string] is handled as if it is sql.NullString, Option[time.Time] is handled as if it is sql.NullTime, and so on.
  • Option[T] can be compared by google/go-cmp.
    • Option[T].Equal is implemented sololy for this purpose.

Compare complex values by go-cmp

Although Option[T] can be compared by go-cmp, it has some caveats when T is complex.

  • cmp.Diff may be hard to read because diff of Option[T] is shown as diff of Option[T].String().
  • cmp.Diff does not compare unexported fields of structs by default. On the other hand, Option[T].Equal is based on reflect.DeepEqual, which compares unexported fields.

You can use cmp.Transformer in such case.

type NestedData struct {
	Value string
}

type TestData struct {
	Value  string
	Nested *NestedData
}

func TestGoCmp(t *testing.T) {
	// Use *T instead of Option[T] in the cmp.Diff.
	cmpopt := cmp.Transformer("options.Option", options.Pointer[*TestData])

	d1 := options.New(&TestData{
		Value: "test",
		Nested: &NestedData{
			Value: "test",
		},
	})
	d2 := options.New(&TestData{
		Value: "test",
		Nested: &NestedData{
			Value: "test2",
		},
	})

	if diff := cmp.Diff(d1, d2, cmpopt); diff != "" {
		t.Errorf("diff:\n%s", diff)
	}
}

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Pointer

func Pointer[T any](o Option[T]) *T

Pointer is a free function version of Option.Pointer.

This function is provided to write Transfermer of go-cmp. See README for details.

Types

type Option

type Option[T any] struct {
	// contains filtered or unexported fields
}

Option[T] represents an optional value of type T.

Options that have no value are called None. The zero value of Option[T] is None.

func FromPointer

func FromPointer[T any](ptr *T) Option[T]

FromPointer creates Option[T] from a pointer. If the pointer is nil, None is returned. Otherwise, a new Option[T] with the pointed value is returned.

func FromTuple deprecated

func FromTuple[T any](value T, present bool) Option[T]

FromTuple is an alias of Pack.

Deprecated: newer code should use Pack instead of this function.

func Map

func Map[A any, B any](o Option[A], f func(A) B) Option[B]

Map returns a new option by applying the given function to the value of the option. If the option is None, None is returned.

Example
package main

import (
	"fmt"

	"github.com/cybozu-go/options"
)

func main() {
	getLength := func(s string) int { return len(s) }

	some := options.New("hello")
	fmt.Printf("some: %#v\n", options.Map(some, getLength))

	none := options.None[string]()
	fmt.Printf("none: %#v\n", options.Map(none, getLength))

}
Output:

some: options.New(5)
none: options.None[int]()

func New

func New[T any](value T) Option[T]

New returns a new Option[T] with the given value.

func None

func None[T any]() Option[T]

None returns a new Option[T] with no value.

func Pack added in v0.3.0

func Pack[T any](value T, present bool) Option[T]

Pack creates Option[T] from (T, bool). If the bool is true, a new Option[T] with the given value is returned. Otherwise, None is returned.

Example
package main

import (
	"fmt"

	"github.com/cybozu-go/options"
)

func main() {
	some := options.Pack(42, true)
	fmt.Println(some.GoString())

	none := options.Pack[int](0, false)
	fmt.Println(none.GoString())

}
Output:

options.New(42)
options.None[int]()

func (Option[T]) Equal

func (o Option[T]) Equal(other Option[T]) bool

Equal returns true if the two options are equal. Equality of the wrapped values is determined by reflect.DeepEqual.

Usually you don't need to call this method since you can use == operator. This method is provided to make Option[T] comparable by go-cmp.

func (Option[T]) GoString

func (o Option[T]) GoString() string

GoString returns the Go representation of the option.

Example
package main

import (
	"fmt"

	"github.com/cybozu-go/options"
)

func main() {
	some := options.New(true)
	fmt.Printf("some: %#v\n", some)

	none := options.None[bool]()
	fmt.Printf("none: %#v\n", none)

}
Output:

some: options.New(true)
none: options.None[bool]()

func (*Option[T]) IsNone

func (o *Option[T]) IsNone() bool

IsNone returns true if the option is None.

func (*Option[T]) IsPresent

func (o *Option[T]) IsPresent() bool

IsPresent returns true if the option has a value.

func (Option[T]) MarshalJSON

func (o Option[T]) MarshalJSON() ([]byte, error)

MarshalJSON implements the json.Marshaler interface.

func (*Option[T]) Pointer

func (o *Option[T]) Pointer() *T

Pointer returns a pointer to the wrapped value of the option. If the option is None, nil is returned.

func (*Option[T]) Scan

func (o *Option[T]) Scan(src any) error

Scan implements the SQL driver.Scanner interface. See http://jmoiron.net/blog/built-in-interfaces

func (Option[T]) String

func (o Option[T]) String() string

String returns the string representation of the wrapped value. If the option is None, an empty string is returned.

Example
package main

import (
	"fmt"

	"github.com/cybozu-go/options"
)

func main() {
	some := options.New(true)
	fmt.Println("some:", some.String())

	none := options.None[bool]()
	fmt.Println("none:", none.String())

}
Output:

some: true
none:

func (*Option[T]) UnmarshalJSON

func (o *Option[T]) UnmarshalJSON(bytes []byte) error

UnmarshalJSON implements the json.Unmarshaler interface.

func (*Option[T]) Unpack added in v0.3.0

func (o *Option[T]) Unpack() (T, bool)

Unpack returns (value, present). If the option is None, value is always zero. This function is useful when you want to check the presence of the value and get it at once.

Example
package main

import (
	"fmt"

	"github.com/cybozu-go/options"
)

func main() {
	some := options.New("hello")
	if s, ok := some.Unpack(); ok {
		fmt.Println(s)
	}

	none := options.None[string]()
	if s, ok := none.Unpack(); ok {
		fmt.Println(s)
	}

}
Output:

hello

func (*Option[T]) Unwrap

func (o *Option[T]) Unwrap() T

Unwrap returns the value of the option. If the option is None, Unwrap panics. You should check the option with Option.IsPresent before calling this method.

Example
package main

import (
	"fmt"

	"github.com/cybozu-go/options"
)

func main() {
	opt := options.New(42)
	fmt.Println(opt.Unwrap())
}
Output:

42

func (*Option[T]) UnwrapOr

func (o *Option[T]) UnwrapOr(defaultValue T) T

UnwrapOr returns the value of the option. If the option is None, the given default value is returned.

Example
package main

import (
	"fmt"

	"github.com/cybozu-go/options"
)

func main() {
	some := options.New(42)
	fmt.Println(some.UnwrapOr(-1))

	none := options.None[int]()
	fmt.Println(none.UnwrapOr(-1))

}
Output:

42
-1

func (*Option[T]) UnwrapOrZero

func (o *Option[T]) UnwrapOrZero() T

UnwrapOrZero returns the value of the option. If the option is None, the zero value of T is returned.

Example
package main

import (
	"fmt"

	"github.com/cybozu-go/options"
)

func main() {
	some := options.New(42)
	fmt.Println(some.UnwrapOrZero())

	none := options.None[int]()
	fmt.Println(none.UnwrapOrZero())

}
Output:

42
0

func (Option[T]) Value

func (o Option[T]) Value() (driver.Value, error)

Value implements the SQL driver.Valuer interface. See http://jmoiron.net/blog/built-in-interfaces

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL