Skip to content

Instantly share code, notes, and snippets.

@travisjeffery
Last active April 23, 2023 11:13
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save travisjeffery/8265ca411735f638db80e2e34bdbd3ae to your computer and use it in GitHub Desktop.
Save travisjeffery/8265ca411735f638db80e2e34bdbd3ae to your computer and use it in GitHub Desktop.
How to do functional options in Golang

Here's the simplest example showing how to do functional options in Golang.

They're a great way to enable users to set options and ease adding new options later.

package main

import (
	"flag"
	"fmt"
)

// This is your function used by users to set options.
func Host(host string) func(*Server) {
	return func(s *Server) {
		s.Host = host
	}
}

// This is another function used by users to set options.
func Port(port int) func(*Server) {
	return func(s *Server) {
		s.Port = port
	}
}

// This is the type whose options you're enabling users to set.
type Server struct {
	Host string
	Port int
}

// This is your creator function that accepts a list of option functions.
func NewServer(opts ...func(*Server)) *Server {
	s := &Server{}

	// call option functions on instance to set options on it
	for _, opt := range opts {
		opt(s)
	}

	return s
}

func main() {
	var host = flag.String("host", "127.0.0.1", "host")
	var port = flag.Int("port", 8000, "port")
	flag.Parse()

	// This is how your user sets the options.
	s := NewServer(
		Host(*host),
		Port(*port),
	)

	fmt.Printf("server host: %s, port: %d", s.Host, s.Port)
}
@melekes
Copy link

melekes commented Feb 10, 2020

Cool! Thank you

@doncatnip
Copy link

doncatnip commented May 7, 2020

So much boilerplate for something so simple. It's quite ridiculous. Google says they do it to avoid bad practices but instead they open pandoras box of bad practices with a restriction like this because now everyone comes up with their own ad hoc solution. It makes code potentially unreadable and forces developers to get creative. The exact opposite of go's goals.

I'm sure they will add some proper sane syntax for optional parameters at some point.

By the way not only is this 'solution' extremely verbose, it's also far from perfect. I.e. you can specify multiple Ports and Hosts. You can also set those parameters after initialization which is not exactly what you want for a Server.

Sorry for that totally off-topic rant but maybe those are necessary.

@logrusorgru
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment