I've found myself using the following pattern as a way to get optional parameters with defaults in Go struct constructors:
package main
import (
"fmt"
)
type Object struct {
Type int
Name string
}
func NewObject(obj *Object) *Object {
if obj == nil {
obj = &Object{}
}
// Type has a default of 1
if obj.Type == 0 {
obj.Type = 1
}
return obj
}
func main() {
// create object with Name="foo" and Type=1
obj1 := NewObject(&Object{Name: "foo"})
fmt.Println(obj1)
// create object with Name="" and Type=1
obj2 := NewObject(nil)
fmt.Println(obj2)
// create object with Name="bar" and Type=2
obj3 := NewObject(&Object{Type: 2, Name: "foo"})
fmt.Println(obj3)
}
Is there a better way of allowing for optional parameters with defaults?
The approach seems reasonable to me. However, you have a bug. If I explicitly set
Type
to 0, it will get switched to 1.My suggested fix: Use a struct literal for the default value: http://play.golang.org/p/KDNUauy6Ie
Or perhaps extract it out: http://play.golang.org/p/QpY2Ymze3b
Take a look at "Allocation with new" in Effective Go. They explain about making zero-value structs a useful default.
If you can make
Object.Type
(and your other fields) have a default of zero, then Go struct literals already give you exactly the feature you're requesting.From the section on composite literals:
That means you can replace this:
with this:
If it is not possible to make the zero value the default for all of your fields, the recommended approach is a constructor function. For example:
If you want
Type
to have a nonzero default, you can add another constructor function. SupposeFoo
objects are the default and haveType
1.You only need to make one constructor function for each set of nonzero defaults you use. You can always reduce that set by changing the semantics of some fields to have zero defaults.
Also, note that adding a new field to
Object
with a zero default value doesn't require any code changes above, because all struct literals use labeled initialization. That comes in handy down the line.Dave Cheney offered a nice solution to this where you have functional options to overwrite defaults:
https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
So your code would become:
https://play.golang.org/p/pGi90d1eI52
https://play.golang.org/p/SABkY9dbCOD
Here's an alternative that uses a method of the object to set defaults. I've found it useful a few times, although it's not much different than what you have. This might allow better usage if it's part of a package. I don't claim to be a Go expert, maybe you'll have some extra input.
Output:
You could use the ... operator.
instead of writing ToCall(a=b) like in python you write, ToCall("a",b)
See the Go Play Example