Skip to content

Instantly share code, notes, and snippets.

@thexpand
Last active January 24, 2023 10:08
Show Gist options
  • Save thexpand/1bfcdf89192f2947c29ade17bd0647c2 to your computer and use it in GitHub Desktop.
Save thexpand/1bfcdf89192f2947c29ade17bd0647c2 to your computer and use it in GitHub Desktop.
Go: Optional parameters

Go: Otional arguments for variadic functions

Check out the optional.go file for more details on the usage.

package main
import (
"example/optional"
"fmt"
)
func main() {
say("world")
say("hello", SayArgs{withExclamationMark: optional.Arg(true)})
}
type SayArgs struct {
milliseconds *optional.ArgType[int]
withExclamationMark *optional.ArgType[bool]
}
func say(s string, args ...SayArgs) {
opts := optional.GetOpts(&args)
milliseconds := optional.Get(opts.milliseconds, 100)
withExclamationMark := optional.Get(opts.withExclamationMark, false)
if withExclamationMark {
s = fmt.Sprint(s, "!")
}
fmt.Println(s)
}
// Package optional deals with cases where you would like to have optional arguments for a function.
package optional
// ArgType is used to define optional arguments of a function.
// Typically, the type function will have the optional arguments
// that are defined as a struct, placed as a last argument(s) of the function.
// An example:
//
// type MyFunctionArgs struct {
// someInt *optional.ArgType[int]
// someBool *optional.ArgType[bool]
// }
//
// func MyFunction(someRequiredString string, args ...MyFunctionArgs) {}
type ArgType[T any] struct {
Value T
}
// Arg is used in function calls to pass optional arguments.
// It returns a pointer to an ArgType that is expected by the function with optional arguments.
//
// If the function uses a struct to hold the optional arguments
// you could pass them and use optional.Arg(value) to pass a different
// value for the function instead of the default one.
//
// Here's an example:
// MyFunction("some required string", MyFunctionArgs{someBool: optional.Arg(true)})
//
// There is no need to provide the generic type, as it can be inferred
// from the value you pass as an argument to this function.
func Arg[T any](Value T) *ArgType[T] {
return &ArgType[T]{Value}
}
// GetOpts transforms the slice argument of the variadic function (taking only
// the first item from the slice) into a single args struct instance.
// If the slice is empty, then an empty struct instance will be returned.
//
// An example of the usage inside a function:
//
// func MyFunction(someRequiredString string, args ...MyFunctionArgs) {
// opts := optional.GetOpts(&args)
// }
func GetOpts[T any](opts *[]T) *T {
if len(*opts) > 0 {
return &(*opts)[0]
}
var empty T
return &empty
}
// Get returns a default value or the one from the option if it's not nil.
// Here is a full example of a function that has its optional arguments
// defined as a struct and how the default values are provided.
//
// type MyFunctionArgs struct {
// someInt *optional.ArgType[int]
// someBool *optional.ArgType[bool]
// }
//
// func MyFunction(someRequiredString string, args ...MyFunctionArgs) {
// opts := optional.GetOpts(&args)
// someInt := optional.Get(opts.someInt, 100)
// someBool := optional.Get(opts.someBool, false)
// }
//
// There is no need to provide the generic type, as it can be inferred
// from the option (from the struct) and from the type of the defaultValue.
func Get[T any](option *ArgType[T], defaultValue T) T {
if option != nil {
return option.Value
}
return defaultValue
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment