Skip to content

Instantly share code, notes, and snippets.

@joyrexus
Created February 21, 2015 14:21
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save joyrexus/33d2e059ab5812ee7f0f to your computer and use it in GitHub Desktop.
Save joyrexus/33d2e059ab5812ee7f0f 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