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 stringCreate 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.