Optional Parameters in Go?

For arbitrary, potentially large number of optional parameters, a nice idiom is to use Functional options.

For your type Foobar, first write only one constructor:

func NewFoobar(options ...func(*Foobar) error) (*Foobar, error){
  fb := &Foobar{}
  // ... (write initializations with default values)...
  for _, op := range options{
    err := op(fb)
    if err != nil {
      return nil, err
    }
  }
  return fb, nil
}

where each option is a function which mutates the Foobar. Then provide convenient ways for your user to use or create standard options, for example :

func OptionReadonlyFlag(fb *Foobar) error {
  fb.mutable = false
  return nil
}

func OptionTemperature(t Celsius) func(*Foobar) error {
  return func(fb *Foobar) error {
    fb.temperature = t
    return nil
  }
}

Playground

For conciseness, you may give a name to the type of the options (Playground) :

type OptionFoobar func(*Foobar) error

If you need mandatory parameters, add them as first arguments of the constructor before the variadic options.

The main benefits of the Functional options idiom are :

  • your API can grow over time without breaking existing code, because the constuctor signature stays the same when new options are needed.
  • it enables the default use case to be its simplest: no arguments at all!
  • it provides fine control over the initialization of complex values.

This technique was coined by Rob Pike and also demonstrated by Dave Cheney.


A nice way to achieve something like optional parameters is to use variadic args. The function actually receives a slice of whatever type you specify.

func foo(params ...int) {
    fmt.Println(len(params))
}

func main() {
    foo()
    foo(1)
    foo(1,2,3)
}

You can use a struct which includes the parameters:

type Params struct {
  a, b, c int
}

func doIt(p Params) int {
  return p.a + p.b + p.c 
}

// you can call it without specifying all parameters
doIt(Params{a: 1, c: 9})

Go does not have optional parameters nor does it support method overloading:

Method dispatch is simplified if it doesn't need to do type matching as well. Experience with other languages told us that having a variety of methods with the same name but different signatures was occasionally useful but that it could also be confusing and fragile in practice. Matching only by name and requiring consistency in the types was a major simplifying decision in Go's type system.

Tags:

Overloading

Go