option

package module
v1.3.1 Latest Latest
Warning

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

Go to latest
Published: Jul 3, 2024 License: MIT Imports: 5 Imported by: 0

README

CircleCI codecov PkgGoDev Go Report Card

Go Option

The idea is based on Scala Option and Java Optional. The package allows to create optional values in Golang.

Features

  • Optional Values: This module introduces the Option[T] type, which represents optional values. An Option[T] either contains a value of type T (represented as Some(T)) or no value at all (represented as None).
  • Safe Handling of Missing Values: The Option[T] type encourages safer handling of missing values, avoiding null pointer dereferences. It can be checked for its state (whether it's Some or None) before usage, ensuring that no nil value is being accessed.
  • Functional Methods: The module provides functional methods such as Map, FlatMap etc. that make operations on Option[T] type instances easy, clear, and less error-prone.
  • Pattern Matching: The Match function allows for clean and efficient handling of Option[T] instances. Depending on whether the Option[T] is Some or None, corresponding function passed to Match get executed, which makes the code expressive and maintains safety.
  • Equality Check: The Equal method provides an efficient way to compare two Option[T] instances, checking if they represent the same state and hold equal values.
  • Generics-Based: With Generics introduced in Go, the module offers a powerful, type-safe alternative to previous ways of handling optional values.
  • Json serialization and deserialization: Build-in json support

Example

Let's check an example without using options

type userModel struct {
	carModel *carModel
}

type carModel struct {
	name        string
	plateNumber *string
}

type User struct {
	car *Car
}

type Car struct {
	name           string
	hasPlateNumber bool
}

func getUser(user userModel) User {
	if user.carModel != nil {
		hasPlateNumber := false
		if user.carModel.plateNumber != nil {
			hasPlateNumber = true
		}
		return User{car: &Car{
			name:           user.carModel.name,
			hasPlateNumber: hasPlateNumber,
		}}
	}
	return User{car: nil}
}

Now the same code with options

type userModel struct {
	carModel Option[carModel]
}

type carModel struct {
	name        string
	plateNumber Option[string]
}

type User struct {
	car Option[Car]
}

type Car struct {
	name           string
	hasPlateNumber bool
}

func getUser(user userModel) User {
	return User{
		car: Map[carModel, Car](user.carModel, func(model carModel) Car {
		    // if model is Some[carModel], transform it to Some[Car]
			return Car{
				name:           model.name,
				hasPlateNumber: model.plateNumber.NonEmpty(),
			}
		}),
	}
}

Functions

Set a non-empty value:

option.Some[int](10)
option.Some(10) // short style

Set an empty value:

v := option.None[int]() 

Set an empty value if v is nil, otherwise set non-empty value

v := option.NewOption[int](10)
v := option.NewOption(10) // short style

Convert pointer to an object to an option

v := option.NewOptionFromPointer[Car](nil) // None[Car]
v := option.NewOptionFromPointer[Car](&Car{}) // Some[Car]
v := option.NewOptionFromPointer(&Car{}) // Some[Car] // short style

Map: Option transformation. Transform underlying value of option to another non option value

import "github.com/martianoff/go-option"

type Car struct {
    name        string
    plateNumber option.Option[string]
}

carOpt := option.Some[Car](
    Car {
        name:        "bmw"
    },
)

// get car name as option
carNameOpt := option.Map[Car, string](carOpt, func(c Car) string {
   return c.name
})

FlatMap: Option composition. Transform underlying value of option to another option value and flat them to an option

import "github.com/martianoff/go-option"

type Car struct {
    name        string
    plateNumber option.Option[string]
}

type User struct {
    name string
    car  option.Option[Car]
}

u := User{
    name: "jake",
    car: option.Some[Car](
        Car{
            name:        "bmw",
            plateNumber: option.Some[string]("X723"),
        },
    ),
}

// get car plate as option
carPlateOpt := option.FlatMap[Car, string](u.car, func(c Car) option.Option[string] {
    return c.plateNumber
})

Methods of Option

Method Description
Get() gets underlying value (unsafe*)
GetOrElse(fallback) gets underlying value or returns fallback value
OrElse(fallbackOpt) returns fallback option if option is empty
Empty() checks if value is empty
NonEmpty() checks if value is set
String() string representation
* - empty value will panic

Pattern matching

Pattern matching is the ability to check and manipulate the value inside the Option[T] type safely without having to manually check the existence of the value every time. It likens to 'pattern matching'

The Match function takes three parameters: Option[T1], and two functions (func(T1) T2).feature found in traditional functional languages. This function behaves differently depending on whether the given Option[T1] is Some or None:

  • If Option[T1] contains a value (or, in other words, it's a Some), the function applies the first provided function func(T1) T2 on this value, aiming to transform it into a new T2 type value.
  • If Option[T1] is None, meaning it does not contain a value, the second provided function func(T1) T2 is applied. Typically, this function should handle the case when no value is present, e.g., by providing a default value, handling an error, etc.
func getCarPlate(plateNumber Option[string]) string {
	return Match(plateNumber, func(p string) string {
		return p
	}, func() string {
		return "N/A"
	})
}

Json serialization and deserialization

Build-in serialization and deserialization

Custom equality

Custom equality powered by github.com/google/go-cmp/cmp

cmp.Equal(Some(11), Some(11)) // returns true

Testing

To run all tests in this module:

go test ./...

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Match added in v1.3.0

func Match[T1, T2 any](opt Option[T1], onSome func(T1) T2, onNone func() T2) T2

Match takes in a current Option 'opt', a function 'onSome' and 'onNone'. 'onSome' gets executed when 'opt' is Some and 'onNone' gets executed when 'opt' is None.

Types

type Option

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

func FlatMap

func FlatMap[T1, T2 any](opt Option[T1], mapper func(T1) Option[T2]) Option[T2]

FlatMap applies the function 'mapper' to the Option 'opt' if it is a Some and returns a new Option. If 'opt' is a None, the function 'mapper' is not applied and Option representing no value is returned.

func Map

func Map[T1, T2 any](opt Option[T1], mapper func(T1) T2) Option[T2]

Map applies the function 'mapper' to the Option 'opt' if it is a Some and returns a new Option. If 'opt' is a None, the function 'mapper' is not applied.

func NewOption

func NewOption[T any](o T) Option[T]

NewOption creates an Option, initializing it with value 'o'. If 'o' is a nil pointer, map, slice, func, interface or channel, the Option will represent no value.

func NewOptionFromPointer added in v1.2.0

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

NewOptionFromPointer creates an Option from input pointer 'o'. If 'o' is nil, it returns an Option representing no value.

func None

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

None returns an Option of Type T which represents no value.

func Some

func Some[T any](o T) Option[T]

Some returns an Option of Type T with value 'o'.

func (Option[T]) Equal added in v1.1.0

func (x Option[T]) Equal(y Option[T]) bool

Equal checks if the calling Option 'x' and the provided Option 'y' are equal. Returns true if both Options are None or both Options are Some and hold the same value.

func (Option[T]) MarshalJSON added in v1.1.0

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

MarshalJSON - custom JSON marshalling for Option

func (*Option[T]) UnmarshalJSON added in v1.1.0

func (opt *Option[T]) UnmarshalJSON(data []byte) error

UnmarshalJSON - custom JSON unmarshalling for Option

Jump to

Keyboard shortcuts

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