create

Go Reference

Package create provides a generic option pattern for creating new values of any type.

Install

go get github.com/norunners/create

Requires Go 1.18 or higher.

Examples

The Greeting type will be created throughout the examples.

type Greeting string

New with options

Create a Greeting with earth as the noun option.

greeting, err := create.New[Greeting](WithNoun("earth"))

Hello earth!

New without options

Create a Greeting without options so the defaults are used.

greeting, err := create.New[Greeting, *GreetingBuilder]()

Hello world!

Builder

Defining GreetingBuilder as a struct allows fields to be added over time.

type GreetingBuilder struct {
	noun string
}

Builder.Default

The Default method provides sensible default values.

func (*GreetingBuilder) Default() *GreetingBuilder {
	return &GreetingBuilder{
		noun: "world",
	}
}

Options

Defining GreetingOption allows functional options on the GreetingBuilder type.
Option WithNoun assigns a value to the noun field, which is not exported.

type GreetingOption func(*GreetingBuilder)

func WithNoun(noun string) GreetingOption {
	return func(b *GreetingBuilder) {
		b.noun = noun
	}
}

Builder.Build

The Build method validates the noun field and creates a new Greeting.

func (b *GreetingBuilder) Build() (Greeting, error) {
	if b.noun == "" {
		return "", fmt.Errorf("empty noun")
	}
	return Greeting(fmt.Sprintf("Hello %s!", b.noun)), nil
}

Instantiation

This instantiates NewGreeting from create.New.
All parameterized types are required for instantiation, e.g. no type inference.

var NewGreeting = create.New[Greeting, *GreetingBuilder, GreetingOption]
greeting, err := NewGreeting(...)

This can be useful as a package scoped variable, e.g. greeting.New.

Satisfy the Builder interface

This ensures GreetingBuilder satisfies create.Builder.

var _ create.Builder[Greeting, *GreetingBuilder] = (*GreetingBuilder)(nil)

Benefits

  1. A single future-proof function to create values.
  2. Provide sensible defaults for any type.
  3. Override defaults with options.
  4. Validate values before creation.
  5. Zero dependencies.

Why?

This is a bit of an experimental exercise of generics in Go
but could also be seen as a standardized way to use the option pattern.

References

License