Skip to content

Instantly share code, notes, and snippets.

@doylecnn
Forked from joyrexus/README.md
Created October 6, 2018 23:57
Show Gist options
  • Save doylecnn/2ab41b4aef0003a34cde543f291928a7 to your computer and use it in GitHub Desktop.
Save doylecnn/2ab41b4aef0003a34cde543f291928a7 to your computer and use it in GitHub Desktop.

Revisions

  1. J. Voigt revised this gist Feb 21, 2015. 1 changed file with 0 additions and 2 deletions.
    2 changes: 0 additions & 2 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,3 @@
    # Functional Configuration

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

  2. J. Voigt created this gist Feb 21, 2015.
    13 changes: 13 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,13 @@
    # Functional Configuration

    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"](http://commandcenter.blogspot.com.au/2014/01/self-referential-functions-and-design.html)) and Dave Cheney (["Functional options for friendly APIs"](http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis)) for more details on this technique.
    30 changes: 30 additions & 0 deletions main.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,30 @@
    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}
    }
    54 changes: 54 additions & 0 deletions person.go
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,54 @@
    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
    }