Skip to content

Instantly share code, notes, and snippets.

@doylecnn
Forked from joyrexus/README.md
Created October 6, 2018 23:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save doylecnn/2ab41b4aef0003a34cde543f291928a7 to your computer and use it in GitHub Desktop.
Save doylecnn/2ab41b4aef0003a34cde543f291928a7 to your computer and use it in GitHub Desktop.
Functional config in go

Quick demo of how to initialize your data structure with optional configuration parameters ... with sane defaults if left unspecified.

This functional config technique ...

  • lets you write APIs that can evolve without pain
  • provides meaningful configuration parameters
  • makes it easy to set default settings
  • makes it possible to set complex conditional values

See the posts by Rob Pike ("Self-referential functions and the design of options") and Dave Cheney ("Functional options for friendly APIs") for more details on this technique.

package main
import (
"fmt"
"github.com/joyrexus/person"
)
func main() {
bill, _ := person.New("Bill") // sets defaults for Job, Age, Alive
fmt.Printf("%#v\n", bill)
// {Name:"Bill", Age:0, Job:"unknown", Alive:true}
bob, _ := person.New("Bob", person.Job("programmer"),
person.Age(44))
fmt.Printf("%#v\n", bob)
// {Name:"Bob", Age:44, Job:"programmer", Alive:true}
// change bob's configuration
bob.Config(person.Age(33),
person.Job("masseuse"),
person.Alive(false))
fmt.Printf("%#v\n", bob)
// {Name:"Bob", Age:33, Job:"masseuse", Alive:false}
}
package person
import "fmt"
type Person struct{
Name string
Age int
Job string
Alive bool
}
func (p *Person) String() string {
return fmt.Sprintf("%s, %v, %s, %v", p.Name, p.Age, p.Job, p.Alive)
}
type option func(*Person)
// Config sets the options specified.
func (p *Person) Config(opts ...option) {
for _, opt := range opts {
opt(p)
}
}
func Age(yrs int) option {
return func(p *Person) {
p.Age = yrs
}
}
func Job(job string) option {
return func(p *Person) {
p.Job = job
}
}
func Alive(status bool) option {
return func(p *Person) {
p.Alive = status
}
}
func New(name string, options ...option) (*Person, error) {
p := Person{
Name: name,
Age: 0,
Job: "unknown",
Alive: true,
}
for _, opt := range options {
opt(&p)
}
return &p, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment