optional

package
v0.0.6 Latest Latest
Warning

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

Go to latest
Published: May 24, 2025 License: MIT Imports: 3 Imported by: 0

Documentation

Overview

Package optional provides a generic Optional type for Go.

For a lot of use cases, I don't like mixing the concepts of referencing and optionality, as it happens with pointers, so this provides an alternative.

The Optionals implemented in this package handle marshalling and unmarshalling to/from json and xml and are handling null-values, not existing values and omitzero/omitempty.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Optional

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

Optional represents a value of type T that may or may not be present.

func Empty

func Empty[T any]() Optional[T]

Empty creates a new empty Optional.

func Of

func Of[T any](value T) Optional[T]

Of creates a new present Optional with the given value.

func (Optional[T]) Get

func (o Optional[T]) Get() (value T, ok bool)

Get returns the value if present, and a boolean indicating its presence.

Example
package main

import (
	"fmt"

	"github.com/KrischanCS/go-toolbox/optional"
)

func main() {
	optPresent := optional.Of("value")
	optEmpty := optional.Empty[string]()

	value, ok := optPresent.Get()
	fmt.Printf("value 1:%s\n", value)
	fmt.Printf("ok 1:%t\n", ok)

	fmt.Println()

	value, ok = optEmpty.Get()
	fmt.Printf("value 2:%s\n", value)
	fmt.Printf("ok 2:%t\n", ok)

}
Output:

value 1:value
ok 1:true

value 2:
ok 2:false

func (Optional[T]) MarshalJSON

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

MarshalJSON encodes marshals the value if present or 'null' if empty.

Example
package main

import (
	"encoding/json"
	"fmt"

	"github.com/KrischanCS/go-toolbox/optional"
)

func main() {
	type Test struct {
		Value1 optional.Optional[string] `json:"value1"`
		Value2 optional.Optional[string] `json:"value2"`
		Value3 optional.Optional[string] `json:"value3,omitempty"` // omitempty will be kept, event if optional is empty
		Value4 optional.Optional[string] `json:"value4,omitzero"`  // omitzero will correctly omit an empty optional
	}

	t := Test{
		Value1: optional.Of("value1"),
		Value2: optional.Empty[string](),
		// Not setting Value3 & Value4, zero values are empty optionals,
		// equivalent as setting Value2 to empty explicitly
	}

	jsonBytes, err := json.MarshalIndent(t, "", "  ")
	if err != nil {
		panic(err)
	}

	fmt.Println(string(jsonBytes))

}
Output:

{
  "value1": "value1",
  "value2": null,
  "value3": null
}

func (Optional[T]) MarshalXML

func (o Optional[T]) MarshalXML(e *xml.Encoder, start xml.StartElement) error

MarshalXML encodes the value if present, otherwise it does nothing (Currently always omitemtpy behaviour).

Example
package main

import (
	"encoding/xml"
	"fmt"

	"github.com/KrischanCS/go-toolbox/optional"
)

func main() {
	type Test struct {
		Value1 optional.Optional[string] `xml:"value1"`
		Value2 optional.Optional[string] `xml:"value2"`           // empty existing tags are considered existing empty strings
		Value3 optional.Optional[string] `xml:"value3,omitempty"` // omitempty will be kept, event if optional is empty
	}

	t := Test{
		Value1: optional.Of("value1"),
		Value2: optional.Empty[string](),
		// Not setting Value3 & Value4, zero values are empty optionals, equivalent as setting Value2 to empty explicitly
	}

	xmlBytes, err := xml.MarshalIndent(t, "", "  ")
	if err != nil {
		panic(err)
	}

	fmt.Println(string(xmlBytes))

}
Output:

<Test>
  <value1>value1</value1>
</Test>

func (Optional[T]) String

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

String returns a string representation in the format:

  • If Present: Optional[{{type}}]: {{value}}
  • If Empty: Optional[{{type}}]: <empty>
Example
package main

import (
	"fmt"

	"github.com/KrischanCS/go-toolbox/optional"
)

func main() {
	optPresent := optional.Of("value")
	optEmpty := optional.Empty[string]()

	fmt.Println(optPresent.String())
	fmt.Println(optEmpty.String())

}
Output:

(Optional[string]: value)
(Optional[string] <empty>)

func (*Optional[T]) UnmarshalJSON

func (o *Optional[T]) UnmarshalJSON(d []byte) error

UnmarshalJSON creates a present Optional if the value is not 'null', otherwise an empty.

Example
package main

import (
	"encoding/json"
	"fmt"

	"github.com/KrischanCS/go-toolbox/optional"
)

func main() {
	type Test struct {
		Value1 optional.Optional[string] `json:"value1"`
		Value2 optional.Optional[string] `json:"value2"`
		Value3 optional.Optional[string] `json:"value3"`
	}

	jsonBytes := []byte(`{"value1":"value1","value2":null}`)

	var t Test
	if err := json.Unmarshal(jsonBytes, &t); err != nil {
		panic(err)
	}

	fmt.Println(t.Value1.String())
	fmt.Println(t.Value2.String())
	fmt.Println(t.Value3.String())

}
Output:

(Optional[string]: value1)
(Optional[string] <empty>)
(Optional[string] <empty>)

func (*Optional[T]) UnmarshalXML

func (o *Optional[T]) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML creates a present Optional if the value is not empty, otherwise an empty.

Example
package main

import (
	"encoding/xml"
	"fmt"

	"github.com/KrischanCS/go-toolbox/optional"
)

func main() {
	type Test struct {
		Value1 optional.Optional[string] `xml:"value1"`
		Value2 optional.Optional[string] `xml:"value2"`
		Value3 optional.Optional[string] `xml:"value3"`
	}

	xmlBytes := []byte(`<Test><value1>value1</value1><value2></value2></Test>`)

	var t Test

	err := xml.Unmarshal(xmlBytes, &t)
	if err != nil {
		panic(err)
	}

	fmt.Println(t.Value1.String())
	fmt.Println(t.Value2.String()) // Empty existing tag will be considered existing empty string
	fmt.Println(t.Value3.String())

}
Output:

(Optional[string]: value1)
(Optional[string]: )
(Optional[string] <empty>)

Jump to

Keyboard shortcuts

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