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 novoContador não recebe parâmetros e retorna func() 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

  1. Declaramos i := 0 dentro de novoContador, mas fora da função anônima. Essa variável viverá enquanto a closure existir.
  2. Retornamos uma função anônima func() int que captura i por referência.
  3. Dentro da closure, i++ modifica a variável original, não uma cópia.
  4. return i devolve o valor atualizado.
  5. No main, chamamos novoContador() e guardamos a closure em c.
  6. Cada chamada de c() executa a mesma closure, que acessa o mesmo i.
  7. 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 i dentro da closure: func() int { i := 0; i++; return i } sempre retornaria 1, pois i seria reinicializado a cada chamada.
  • Retornar nil: se esquecer de retornar a função, o programa entra em pânico ao chamar c().
  • Usar i sem incrementar: return i sem i++ 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