Pattern) Local Helper Closure

Local Helper Closure

Local Helper Function

  • A technique of assigning an anonymous function that is only used inside a function to a variable.
  • Minimizes argument passing by capturing variables from the parent function and removes repetitive logic.

e.g.

 1func BuildControllers(ctx context.Context, controllerCtx ControllerContext, controllerDescriptors map[string]*ControllerDescriptor,
 2	unsecuredMux *mux.PathRecorderMux, healthzHandler HealthCheckAdder) ([]Controller, error) {
 3	...
 4	buildController := func(controllerDesc *ControllerDescriptor) error {
 5		controllerName := controllerDesc.Name()
 6		ctrl, err := controllerDesc.BuildController(ctx, controllerCtx)
 7		...
 8		controllers = append(controllers, ctrl)
 9		checks = append(checks, check)
10		return nil
11	}
12	...
13	for _, controllerDesc := range controllerDescriptors {
14		...
15		if err := buildController(controllerDesc); err != nil {
16			return nil, err
17		}
18	}
19	...
20}
Advantages
  • Can eliminate duplicate code
  • Simplified Function Arguments
    • Uses captured external variables instead of function arguments (closure)
  • Share state without global variables
    • Shares local variables within the scope
  • Encapsulation/Isolation
    • Usable only within its scope
Caution
  • Cannot write unit tests
  • From a functional programming perspective, it's an impure function
  • Avoid capturing too many external variables
  • It's best to keep it short for readability
  • Loop Variable Capture Issue
    • Go 1.21 and below: The loop variable (v) is not newly created with each iteration; instead, it continuously overwrites a single memory address
    • Go 1.22 and above: A new variable is created (shadowing) for each iteration of the loop

Post
Category
Series