Literais de Função e Closures
Um literal de função é uma expressão de função anônima que você pode definir e invocar inline.
Busque em todas as páginas da documentação
Um literal de função é uma expressão de função anônima que você pode definir e invocar inline.
Quando ele referencia variáveis de escopos circundantes, torna-se um closure que carrega esses vínculos para execuções posteriores - incluindo goroutines e chamadas adiadas.
Literais de função permitem callbacks locais, middleware e fábricas sem declarar funções de nível superior nomeadas.
Closures capturam variáveis por referência, não por snapshot, a menos que você copie variáveis de loop ou passe parâmetros explicitamente.
O bug clássico de goroutine lança múltiplos closures compartilhando uma variável de loop.
Fábricas retornam closures configurados (limitadores de taxa, validadores) enquanto ocultam o estado mutável na função externa.
Use literais para comportamento curto e local; promova para funções nomeadas quando a lógica crescer ou precisar de testes isolados.
Cartão de receita de referência rápida - pronto para copiar e colar.
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)
})
}
}
// Spawn seguro de goroutine em um loop.
for _, id := range ids {
id := id
go func() {
process(id)
}()
}Quando usar isso:
defer precisa de uma função local ajustando o comportamento de limpeza.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
}O que isso demonstra:
New retorna um closure que oculta mu e last.Limiter.go agenda o closure - as semânticas de captura importam no momento do agendamento, não apenas no momento da definição.| Cenário | Problema | Correção |
|---|---|---|
Variável de loop for | Todas as goroutines veem o valor final | id := id ou passe parâmetro go func(id int){...}(id) |
defer em loop | Adiamentos empilham até a função retornar | Empacote o corpo em literal func(){ defer ... }() |
| Captura mutada | Corridas em variáveis compartilhadas | Serialização com Mutex ou canal |
| Struct grande capturada | Retenção acidental | Capture apenas o ponteiro para o campo necessário |
| Padrão | Força | Fraqueza |
|---|---|---|
| Fábrica de Closure | Superfície de API mínima | Mais difícil de inspecionar estado em testes |
| Struct com métodos | Campos claros, interfaces | Mais boilerplate |
| Alias de tipo de função | Middleware componível | Sem múltiplos métodos |
sort.Slice(items, func(i, j int) bool {
return items[i].Priority < items[j].Priority
})Literais se destacam para comparadores e filtros de uso único.
Extraia quando reutilizado entre pacotes.
v := v ou passe como parâmetro.func(){ defer cleanup(); work() }().func() não inicializado causa pânico. Correção: proteja ou exija construtor.&v em um loop compartilha um endereço. Correção: copie o valor dentro do corpo do loop antes de obter o endereço.Add antes de go causa corrida. Correção: chame Add antes do lançamento; use defer Done() dentro da goroutine.| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
| Função nomeada | Reutilizada, precisa de teste unitário direto | Comparador de uma linha |
| Implementação de interface | Múltiplos métodos, mocks | Único hook |
| Struct + método | Serviço com estado e API clara | Callback pequeno de uso único |
| Canais para coordenação | Estágios de pipeline | Limiter serial simples é suficiente |
Um literal de função é uma sintaxe para uma função anônima.
Torna-se um closure quando referencia variáveis de um escopo externo.
Variáveis são capturadas por referência.
Mutações visíveis para todos os closures que compartilham esse vínculo, a menos que você sombreie por iteração.
Variáveis de loop por iteração reduzem o bug clássico de captura de goroutine.
Ainda prefira parâmetros explícitos em bibliotecas que visam versões mais antigas ou quando a clareza ajuda os leitores.
Sim - retornar um closure de uma fábrica estende o tempo de vida das variáveis capturadas no heap.
http.HandlerFunc é um tipo de função com um método ServeHTTP.
Literais convertem para handlers: http.HandlerFunc(func(w,r){...}).
Valores capturados vivem enquanto o valor do closure existir.
Solte referências a closures para liberar estado retido.
Sim - literais podem aparecer dentro de funções genéricas respeitando parâmetros de tipo.
A assinatura deve corresponder exatamente ao tipo de função exigido.
Use httptest.ResponseRecorder e um handler next stub que registra chamadas.
Extraia o construtor de middleware para uma função nomeada para testes de tabela.
Funções adiadas em closures são executadas na saída da função envolvente.
Regras separadas se aplicam a limites de panic/recover - mantenha o recover na entrada da goroutine quando necessário.
Quando o comportamento é um único hook (Limiter, Validator, AttemptFunc).
Mude para interfaces quando mocks precisarem de múltiplos métodos.
Handlers de longa duração que capturam buffers grandes de escopo de requisição podem vazar.
Capture IDs, não requisições inteiras.
govet e staticcheck sinalizam problemas de defer em loop e captura.
Execute linters em CI em código concorrente.
HandlerFuncVersões da Pilha: Esta página foi escrita para Go 1.26.x (padrão GC Green Tea, go fix modernizers - verifique o patch na compilação), chi (mais recente - verifique na compilação), gin (mais recente - verifique na compilação), echo (mais recente - verifique na compilação), google.golang.org/grpc (mais recente - verifique na compilação), sigs.k8s.io/controller-runtime (mais recente - verifique na compilação), kubebuilder (mais recente - verifique na compilação), tinygo (mais recente - verifique os alvos de placa na compilação), wazero (mais recente - verifique na compilação) e golangci-lint (mais recente - verifique o conjunto de linters na compilação).
Revisado por Chris St. John·Última atualização: 18 de jul. de 2026