Go Funções Intermediário
Closures
Em Go, uma closure é uma função que captura variáveis do escopo onde foi definida. Isso permite criar funções que "lembram" do estado entre chamadas, gerar sequências, criar middlewares e muito mais.
A captura é feita por referência: a closure acessa a variável original, não uma cópia. Isso significa que se a variável mudar depois, a closure verá o novo valor. Esse comportamento é poderoso, mas exige cuidado com concorrência e com loops.
No Go 1.22, a semântica de variáveis de loop mudou: cada iteração cria uma nova variável, então closures criadas dentro do loop capturam valores distintos. Antes, todas as closures compartilhavam a mesma variável, o que causava bugs clássicos.
Closures são usadas em geradores (funções que retornam a próxima função), middlewares (funções que envolvem outras) e para encapsular estado sem criar structs. Entender closures é essencial para escrever código Go idiomático e seguro.
Pontos-chave
- Closures capturam variáveis por referência, não por valor.
- Geradores usam closures para manter estado entre chamadas.
- No Go 1.22+, cada iteração de loop tem sua própria variável, evitando o bug de captura compartilhada.
- Middlewares são closures que recebem e retornam funções, permitindo encadear comportamentos.
- Cuidado com concorrência: closures que capturam variáveis mutáveis podem causar data races.
package main
import "fmt"
// contador retorna uma closure que incrementa e retorna um valor.
func contador() func() int {
i := 0
return func() int {
i++
return i
}
}
// gerador retorna uma closure que gera números pares até um limite.
func geradorPares(limite int) func() (int, bool) {
n := 0
return func() (int, bool) {
if n > limite {
return 0, false
}
valor := n
n += 2
return valor, true
}
}
func main() {
// Closure contadora
c := contador()
fmt.Println(c()) // 1
fmt.Println(c()) // 2
fmt.Println(c()) // 3
// Gerador de pares
prox := geradorPares(6)
for {
v, ok := prox()
if !ok {
break
}
fmt.Println(v)
}
// Loop var no Go 1.22: cada iteração tem sua própria variável
funcs := make([]func(), 3)
for i := 0; i < 3; i++ {
funcs[i] = func() { fmt.Println(i) }
}
for _, f := range funcs {
f()
}
}