Fácil Go
Contador com closure
Enunciado
Crie uma função novoContador que retorna uma closure. A closure deve incrementar um contador interno e retornar o valor atual a cada chamada. No main, crie um contador, chame-o três vezes e imprima os valores.
Requisitos
- A função
novoContadornão recebe parâmetros e retornafunc() int. - A closure mantém o estado entre chamadas.
- As três primeiras chamadas retornam 1, 2 e 3.
Código inicial
package main
import "fmt"
// novoContador retorna uma closure que incrementa um contador.
func novoContador() func() int {
// implemente aqui
return nil
}
func main() {
// use novoContador e imprima os valores
}
Saída esperada
1
2
3
Ver dica
Declare uma variável inteira fora da closure retornada, mas dentro de novoContador. A closure pode acessá-la e modificá-la.
Mostrar solução
package main
import "fmt"
// novoContador retorna uma closure que incrementa um contador interno.
func novoContador() func() int {
i := 0 // variável capturada pela closure
return func() int {
i++ // incrementa o estado compartilhado
return i
}
}
func main() {
c := novoContador()
fmt.Println(c()) // 1
fmt.Println(c()) // 2
fmt.Println(c()) // 3
}
Passo a passo
- Declaramos
i := 0dentro denovoContador, mas fora da função anônima. Essa variável viverá enquanto a closure existir. - Retornamos uma função anônima
func() intque capturaipor referência. - Dentro da closure,
i++modifica a variável original, não uma cópia. return idevolve o valor atualizado.- No
main, chamamosnovoContador()e guardamos a closure emc. - Cada chamada de
c()executa a mesma closure, que acessa o mesmoi. - Os valores impressos são 1, 2 e 3, mostrando que o estado persiste entre chamadas.
Por que funciona
A closure captura a variável i do escopo de novoContador. Mesmo depois que novoContador retorna, i continua existindo porque a closure mantém uma referência a ela. Isso é possível porque Go gerencia o tempo de vida das variáveis capturadas por closures no heap, se necessário.
Erros comuns
- Declarar
identro da closure:func() int { i := 0; i++; return i }sempre retornaria 1, poisiseria reinicializado a cada chamada. - Retornar
nil: se esquecer de retornar a função, o programa entra em pânico ao chamarc(). - Usar
isem incrementar:return isemi++retornaria sempre 0.
Outra forma de resolver
Usar uma struct com método seria mais verboso, mas útil se precisar de mais estado ou métodos. Exemplo:
type Contador struct{ i int }
func (c *Contador) Incrementa() int { c.i++; return c.i }
Prefira closure para estado simples e encapsulado.
Saída esperada
1
2
3