SoFunction
Updated on 2025-03-05

Teach you to use Golang optional parameters to implement optional modes

This article discusses the optional parameters and function types of Golang functions, and how to use optional function types to implement optional modes. At the same time, using constructors as examples, a powerful constructor with optional parameters is implemented, making the code more intuitive, flexible and expandable.

Start with demand

Optional parameters pass additional parameters to the function to extend or modify its behavior. The following example uses optional functions to create a house type:

h := NewHouse(
  WithConcrete(),
  WithoutFireplace(),
)

NewHouseis a constructor,WithConcreteandWithoutFireplaceis an optional parameter to pass in the constructor to modify its return value. Details belowWithConcreteandWithoutFireplaceOptional functional functions, sometimes they are more useful than normal function parameters.

Define the constructor

First define the structure to utilize optional functions:

type House struct {
	Material     string
	HasFireplace bool
	Floors       int
}

// `NewHouse` is a constructor function for `*House`
func NewHouse() *House {
	const (
		defaultFloors       = 2
		defaultHasFireplace = true
		defaultMaterial     = "wood"
	)

	h := &House{
		Material:     defaultMaterial,
		HasFireplace: defaultHasFireplace,
		Floors:       defaultFloors,
	}

	return h
}

HouseIt may be made of different materials, with multiple layers, and may include a fireplace.NewHouseConstructor returnsHousePointer, all attributes include default values. Under normal circumstances, first constructHouse, and then modify the attribute value according to different needs. Using function optional parameters, you can pass a set of modifier functions to the constructor.

Define optional functions

First define the function type, acceptHouseType pointer:

type HouseOption func(*House)

This is the signature of the optional function. The following defines some optional functions for modification*HouseExample:

func WithConcrete() HouseOption {
	return func(h *House) {
		 = "concrete"
	}
}

func WithoutFireplace() HouseOption {
	return func(h *House) {
		 = false
	}
}

Each function above is an optional constructor, returns another function with*HouseParameter, no return value. We see that the returned function has been modified*HouseThe attributes of the instance. Other optional function types can also be implemented to modify parameter instance properties. The following function returns optional functions to modify the floor:

func WithFloors(floors int) HouseOption {
	return func(h *House) {
		 = floors
	}
}

Enhanced constructor

Now combine optional function functions and constructors:

// NewHouse now takes a slice of option as the rest arguments
func NewHouse(opts ...HouseOption) *House {
	const (
		defaultFloors       = 2
		defaultHasFireplace = true
		defaultMaterial     = "wood"
	)

	h := &House{
		Material:     defaultMaterial,
		HasFireplace: defaultHasFireplace,
		Floors:       defaultFloors,
	}

	// Loop through each option
	for _, opt := range opts {
		// Call the option giving the instantiated
		// *House as the argument
		opt(h)
	}

	// return the modified house instance
	return h
}

The constructor accepts any number of optional function functions as parameters. After the House property is initialized for the first time, the optional function function is run accordingly to modify the property value.
Going back to the beginning example, you can now implement a constructor call with optional parameters:

h := NewHouse(
  WithConcrete(),
  WithoutFireplace(),
  WithFloors(3),
)

Advantages of optional modes

The above discusses how to implement optional modes, and here is a summary of its advantages.

Intuitive and clear

Compared to displaying modified object properties:

h := NewHouse()
 = "concrete"

It can be directly implemented using constructors:

h := NewHouse(WithConcrete())

This is clearer, without specifying string values, avoiding typing errors and exposing *house internal details.

Support extensions

Optional mode supports extensions, always supporting different optional function parameters to pass into the constructor. For example, since the floor of the house can be any integer, we provide specific values ​​as parameters to pass into the constructor:

h := NewHouse(WithFloors(4))

Parameter order

The use of optional mode is independent of the parameter order and has great flexibility compared to normal parameters; and, any optional parameters can be provided, and all parameters must be provided compared to normal parameters.

// What `NewHouse` would look like if we used
// regular function arguments
// We would always need to provide all three
// arguments no matter what
h := NewHouse("concrete", 5, true)

This is the end of this article about using Golang optional parameters to implement optional modes. For more relevant Golang optional parameters, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!