Skip to content

Instantly share code, notes, and snippets.

@sponomarev
Forked from joyrexus/README.md
Created October 29, 2018 15:23
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 sponomarev/f10ef3aba4fc5dab59f08e166e548945 to your computer and use it in GitHub Desktop.
Save sponomarev/f10ef3aba4fc5dab59f08e166e548945 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