Literales de Función y Clousures
Un literal de función es una expresión de función anónima que puedes definir e invocar en línea.
Busca en todas las páginas de la documentación
Un literal de función es una expresión de función anónima que puedes definir e invocar en línea.
Cuando hace referencia a variables de ámbitos circundantes, se convierte en un clousure que transporta esas vinculaciones a ejecuciones posteriores, incluyendo goroutines y llamadas diferidas.
Los literales de función permiten callbacks locales, middleware y fábricas sin declarar funciones de nivel superior con nombre.
Los clousures capturan variables por referencia, no por instantánea, a menos que copies variables de bucle o pases parámetros explícitamente.
El error clásico de goroutine lanza múltiples clousures compartiendo una variable de bucle.
Las fábricas devuelven clousures configurados (limitadores de velocidad, validadores) ocultando el estado mutable en la función externa.
Usa literales para comportamientos cortos y locales; promuévelos a funciones con nombre cuando la lógica crezca o necesite pruebas de forma aislada.
Tarjeta de receta de referencia rápida, lista para copiar y pegar.
func withTimeout(parent context.Context, d time.Duration) (context.Context, context.CancelFunc) {
return context.WithTimeout(parent, d)
}
func middleware(log func(string)) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log(r.Method + " " + r.URL.Path)
next.ServeHTTP(w, r)
})
}
}
// Lanzamiento seguro de goroutine en un bucle.
for _, id := range ids {
id := id
go func() {
process(id)
}()
}Cuándo usar esto:
defer necesita una función local que ajuste el comportamiento de limpieza.slices.SortFunc / sort.Slice.package ratelimit
import (
"context"
"sync"
"time"
)
type Limiter func(ctx context.Context) error
func New(interval time.Duration) Limiter {
var mu sync.Mutex
var last time.Time
return func(ctx context.Context) error {
mu.Lock()
defer mu.Unlock()
now := time.Now()
wait := interval - now.Sub(last)
if wait > 0 {
timer := time.NewTimer(wait)
defer timer.Stop()
select {
case <-ctx.Done():
return ctx.Err()
case <-timer.C:
}
}
last = time.Now()
return nil
}
}
func Example(ctx context.Context) error {
wait := New(100 * time.Millisecond)
for i := 0; i < 3; i++ {
if err := wait(ctx); err != nil {
return err
}
}
return nil
}Lo que esto demuestra:
New devuelve un clousure que oculta mu y last.Limiter.go programa el clousure; los semánticas de captura importan en el momento de la programación, no solo en el momento de la definición.| Escenario | Problema | Corrección |
|---|---|---|
Variable de bucle for | Todas las goroutines ven el valor final | id := id o pasar parámetro go func(id int){...}(id) |
defer en bucle | Los defer se apilan hasta que la función retorna | Envuelve el cuerpo en un literal func(){ defer ... }() |
| Captura mutada | Carreras en variables compartidas | Serialización con mutex o canal |
| Estructura capturada grande | Retención accidental | Captura solo el puntero al campo necesario |
| Patrón | Fortaleza | Debilidad |
|---|---|---|
| Fábrica de Clousures | Superficie de API mínima | Más difícil de inspeccionar el estado en pruebas |
| Estructura con métodos | Campos claros, interfaces | Más código repetitivo |
| Alias de tipo de función | Middleware componible | Sin múltiples métodos |
sort.Slice(items, func(i, j int) bool {
return items[i].Priority < items[j].Priority
})Los literales son excelentes para comparadores y filtros de un solo uso.
Extrae cuando se reutiliza en varios paquetes.
v := v o pasa como parámetro.func(){ defer cleanup(); work() }().func() no inicializado provoca un panic. Corrección: protege o requiere un constructor.&v en un bucle comparte una dirección. Corrección: copia el valor dentro del cuerpo del bucle antes de tomar la dirección.Add antes de go provoca una carrera. Corrección: llama a Add antes del lanzamiento; usa defer Done() dentro de la goroutine.| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
| Función con nombre | Reutilizada, necesita prueba unitaria directa | Comparador de una línea |
| Implementación de interfaz | Múltiples métodos, mocks | Hook único |
| Estructura + método | Servicio con estado y API clara | Callback pequeño de un solo uso |
| Canales para coordinación | Etapas de pipeline | Un limitador serial simple es suficiente |
Un literal de función es sintaxis para una función anónima.
Se convierte en un clousure cuando hace referencia a variables de un ámbito externo.
Las variables se capturan por referencia.
Las mutaciones son visibles para todos los clousures que comparten esa vinculación, a menos que sombrees por iteración.
Las variables de bucle por iteración reducen el error clásico de captura de goroutines.
Aún prefiere parámetros explícitos en bibliotecas dirigidas a versiones anteriores o cuando la claridad ayuda a los lectores.
Sí, devolver un clousure de una fábrica extiende la vida útil de las variables capturadas en el heap.
http.HandlerFunc es un tipo de función con un método ServeHTTP.
Los literales se convierten en manejadores: http.HandlerFunc(func(w,r){...}).
Los valores capturados viven mientras exista el valor del clousure.
Elimina referencias a clousures para liberar el estado retenido.
Sí, los literales pueden aparecer dentro de funciones genéricas respetando los parámetros de tipo.
La firma debe coincidir exactamente con el tipo de función requerido.
Usa httptest.ResponseRecorder y un manejador next simulado que registre las llamadas.
Extrae el constructor de middleware a una función con nombre para pruebas de tabla.
Las funciones diferidas en clousures se ejecutan al salir de la función circundante.
Se aplican reglas separadas para los límites de panic/recover; mantén recover en la entrada de la goroutine cuando sea necesario.
Cuando el comportamiento es un solo hook (Limiter, Validator, AttemptFunc).
Cambia a interfaces cuando los mocks necesiten múltiples métodos.
Los manejadores de larga duración que capturan búferes grandes del ámbito de la solicitud pueden tener fugas.
Captura IDs, no solicitudes completas.
govet y staticcheck marcan problemas de defer en bucle y captura.
Ejecuta linters en CI en código concurrente.
HandlerFuncVersiones de Stack: Esta página fue escrita para Go 1.26.x (GC por defecto Green Tea, go fix modernizers - verificar parche en la compilación), chi (última versión - verificar en la compilación), gin (última versión - verificar en la compilación), echo (última versión - verificar en la compilación), google.golang.org/grpc (última versión - verificar en la compilación), sigs.k8s.io/controller-runtime (última versión - verificar en la compilación), kubebuilder (última versión - verificar en la compilación), tinygo (última versión - verificar objetivos de placa en la compilación), wazero (última versión - verificar en la compilación) y golangci-lint (última versión - verificar conjunto de linters en la compilación).
Revisado por Chris St. John·Última actualización: 18 jul 2026