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
}
}
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 :
This technique was coined by Rob Pike and also demonstrated by Dave Cheney.