Understanding the Functional Options Pattern in Go

A quick overview of the Functional Options Pattern in Go.

Introduction

While using a Go-based library, I came across the Functional Options Pattern.

Here's a brief note on what the Functional Options Pattern is in Go.

Note: This article was translated from my original post.

Functional Options Pattern in Go

Here's a minimal implementation of the Functional Options Pattern:

type Coffee struct {
    Sugar int  // Sugar specifies the number of sugar spoons
    Milk  bool // Milk indicates whether milk is added or not
}

type Option func(*Coffee)

func NewCoffee(opts ...Option) *Coffee {
    c := &Coffee{
        Sugar: 0,
        Milk:  false,
    }

    for _, opt := range opts {
        opt(c)
    }

    return c
}


func WithSugar(spoons int) Option {
    return func(c *Coffee) {
        c.Sugar = spoons
    }
}

func WithMilk() Option {
    return func(c *Coffee) {
        c.Milk = true
    }
}

Example usage of NewCoffee():

func main() {
    c1 := NewCoffee()
    c2 := NewCoffee(WithSugar(2))
    c3 := NewCoffee(WithMilk(), WithSugar(1))
}

As you can see, you can define a variadic list of option arguments to NewCoffee.

Inside NewCoffee, default values are set with Coffee{Sugar: 0, Milk: false}, and if any Option-type functions are passed, those functions will override the fields accordingly.

Conclusion

This post introduced the Functional Options Pattern in Go with a minimal example.

For more detailed explanations and background, the following article is highly recommended:

Functional options for friendly APIs | Dave Cheney

Hope this helps someone.

[Related Articles]

en.bioerrorlog.work

References