A closure is a function that retains access to variables in its surrounding scope, including after the outer function returns. It lets a function carry the state or dependencies it needs when that function is called later. section 2.5.2 section 2.5.3
Use closures when behavior needs context that does not fit the eventual function signature. A higher-order function can accept a pointer or dependency, then return a function with a uniform signature that still reaches that captured value. section 4.2.2 section 6.4.1
Bind a flag parser to its destination
A CLI parser can store functions with one parseFunc signature while binding each one to a different configuration field. stringVar receives *string and returns a closure that assigns input; intVar receives *int and returns a closure that converts and assigns input. Calling the stored parser later updates the original field through its captured pointer. section 4.2.2 section 4.2.3
Listing 4.2 Flag value parsers (hit/cmd/hit/config.go)
package main
import "strconv"
type parseFunc func(string) error #1
func stringVar(p *string) parseFunc { #2
return func(s string) error { #3
*p = s #4
return nil
}
}
func intVar(p *int) parseFunc { #5
return func(s string) error {
var err error
*p, err = strconv.Atoi(s) #6
return err
}
}
The returned functions keep their respective pointers while exposing the same parseFunc type, making them suitable for a parser map. section 4.2.2
Closures also adapt function types. A default request sender can capture an HTTP client so it satisfies a simpler SendFunc signature, even though the underlying Send function requires that extra client parameter. This keeps configurable behavior behind one function type. section 6.4.1
Return an HTTP handler with explicit dependencies
A handler factory can accept a logger and URL-shortening service, then return an http.Handler closure. The closure uses those captured dependencies for every request. Passing dependencies directly makes the handler easier to test, since a no-op or inspectable logger can be supplied instead of relying on a global. section 8.4.1
Listing 8.10 Shorten handler (link/rest/shortener.go)
package rest
import (
"fmt"
"log/slog"
"net/http"
"github.com/inancgumus/gobyexample/link"
)
// Shorten returns an [http.Handler] that shortens URLs.
func Shorten(
lg *slog.Logger, links *link.Shortener, #1
) http.Handler { #2
return http.HandlerFunc(func( #3
w http.ResponseWriter, r *http.Request, #3
) { #3
key, err := links.Shorten(r.Context(), link.Link{
Key: link.Key( #4
r.PostFormValue("key"), #4
), #4
URL: r.PostFormValue("url"), #4
})
if err != nil {
httpError(w, r, lg, fmt.Errorf( #5
"shortening: %w", err, #5
)) #5
return #6
}
w.WriteHeader(http.StatusCreated) #7
fmt.Fprint(w, key) #7
})
}
The handler closure captures the logger and shortener, processes a POST request, and returns immediately after writing an error response. section 8.4.1
Closures can retain pointers beyond the creating function's lifetime. Variables referenced by active closures cannot be reclaimed by the garbage collector, so avoid retaining or improperly sharing long-lived closures when that would keep memory alive unnecessarily. In subtests, each Run closure receives its own *testing.T; do not share a test's *testing.T with other tests. section 2.5.3 section 2.5.2



















