Skip to content

Instantly share code, notes, and snippets.

@miroswan
Created May 11, 2021 18:19
Show Gist options
  • Save miroswan/b4e53795f962469e471902365a93030c to your computer and use it in GitHub Desktop.
Save miroswan/b4e53795f962469e471902365a93030c to your computer and use it in GitHub Desktop.
Functional Variadic Arguments as Options
package main
import (
"fmt"
"strings"
)
// consoleOptions is a private structure that contains
// the possible options for a Console. It's private so
// that consumers do not rely on its members. This allows
// the code to be able to be extended without breaking how
// consumers use it.
type consoleOptions struct {
lastNameOption string
shoutOption bool
}
// ConsoleOption is a functional option that can be passed
// to a constructor of a Console. Again, this allows the
// constructor of a Console to be extended without
// breaking the constructor function's signature.
type ConsoleOption func(*consoleOptions)
// LastNameConsoleOption can be passed to the Console's
// constructor function. It adds the last name to the console
// messages.
func LastNameConsoleOption(lastName string) ConsoleOption {
return func(options *consoleOptions) {
options.lastNameOption = lastName
}
}
// ShoutConsoleOption can be passed to the Console's
// constructor function. It makes each console
// message "loud" by making each message upper case.
func ShoutConsoleOption() ConsoleOption {
return func(options *consoleOptions) {
options.shoutOption = true
}
}
// NewConsole returns a pointer to a Console. Note that we
// can add an arbitrary number of options in the future
// without changing the signature of this constructor
// function.
func NewConsole(
firstName string,
optionFunctions ...ConsoleOption,
) *Console {
// load the options passed into the constructor
options := new(consoleOptions)
for _, function := range optionFunctions {
function(options)
}
// Return a pointer to Console, furnished with all
// of the required and optional configuration.
return &Console{
firstName: firstName,
lastNameOption: options.lastNameOption,
shoutOption: options.shoutOption,
}
}
// Console prints messages to STDOUT with some additional information
type Console struct {
firstName string // required
lastNameOption string // optional
shoutOption bool // optional
}
// Print the message to STDOUT
func (c *Console) Print(message string) {
b := new(strings.Builder)
b.WriteString(c.firstName)
b.WriteRune(' ')
// If the lastNameOption is an empty string, then it was not set
if c.lastNameOption != "" {
b.WriteString(c.lastNameOption)
b.WriteRune(' ')
}
// If shoutOption is set, then upcase the message
b.WriteString(": ")
if c.shoutOption {
b.WriteString(strings.ToUpper(message))
} else {
b.WriteString(message)
}
fmt.Println(b.String())
}
func main() {
console := NewConsole(
"Pragmatic", // required argument
LastNameConsoleOption("Coder"), // optional configuration
ShoutConsoleOption(), // optional configuration
)
console.Print("This message has been customized.")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment