Package create
provides a generic option pattern for creating new values of any type.
go get github.com/norunners/create
Requires Go 1.18 or higher.
The Greeting
type will be created throughout the examples.
type Greeting string
Create a Greeting
with earth
as the noun option.
greeting, err := create.New[Greeting](WithNoun("earth"))
Hello earth!
Create a Greeting
without options so the defaults are used.
greeting, err := create.New[Greeting, *GreetingBuilder]()
Hello world!
Defining GreetingBuilder
as a struct allows fields to be added over time.
type GreetingBuilder struct {
noun string
}
The Default
method provides sensible default values.
func (*GreetingBuilder) Default() *GreetingBuilder {
return &GreetingBuilder{
noun: "world",
}
}
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
}
}
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
}
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
.
This ensures GreetingBuilder
satisfies create.Builder
.
var _ create.Builder[Greeting, *GreetingBuilder] = (*GreetingBuilder)(nil)
- A single future-proof function to create values.
- Provide sensible defaults for any type.
- Override defaults with options.
- Validate values before creation.
- Zero dependencies.
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.