Médio Go
Recover em função com defer
Enunciado
Crie uma função safeDivide(a, b int) (result int, err error) que divide a por b. Se b for zero, a função deve entrar em panic e, usando defer e recover, capturar o panic e retornar um erro com a mensagem "divisão por zero". Caso contrário, retorne o resultado e nil.
Requisitos
- Usar
defercom uma função anônima que chamarecover. - Se
b == 0,panicdeve ser acionado e recuperado, retornando erro. - Se
b != 0, retornar o quociente inteiro enil. - O programa principal deve testar ambos os casos e imprimir os resultados.
Código inicial
package main
import "fmt"
func safeDivide(a, b int) (result int, err error) {
// Seu código aqui
}
func main() {
// Teste a função
}
Saída esperada
10 / 2 = 5
10 / 0 = erro: divisão por zero
Ver dica
Dentro do defer, verifique se recover() retornou algo não nulo e atribua ao retorno nomeado err.
Mostrar solução
package main
import "fmt"
func safeDivide(a, b int) (result int, err error) {
// Função anônima adiada para recuperar panic
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("%v", r) // converte o valor do panic em erro
}
}()
if b == 0 {
panic("divisão por zero") // aciona o panic
}
return a / b, nil
}
func main() {
// Caso normal
res, err := safeDivide(10, 2)
if err != nil {
fmt.Printf("10 / 2 = erro: %v\n", err)
} else {
fmt.Printf("10 / 2 = %d\n", res)
}
// Caso de divisão por zero
res, err = safeDivide(10, 0)
if err != nil {
fmt.Printf("10 / 0 = erro: %v\n", err)
} else {
fmt.Printf("10 / 0 = %d\n", res)
}
}
Passo a passo
- A função
safeDividedeclara retornos nomeadosresulteerr. - Imediatamente, um
defercom função anônima é agendado. Dentro dele,recover()captura qualquer panic. - Se
b == 0, a função executapanic("divisão por zero"), interrompendo o fluxo normal. - O panic desenrola a pilha e executa o
defer. Orecover()retorna a string"divisão por zero". - O valor recuperado é atribuído a
errusandofmt.Errorf. O retorno nomeadoresultpermanece zero. - A função retorna
(0, err). - No
main, o erro é verificado e a mensagem apropriada é impressa.
Por que funciona
O defer é executado mesmo quando ocorre um panic, desde que o panic não tenha sido recuperado antes. Como o recover está dentro do defer, ele captura o panic e evita que o programa termine. Os retornos nomeados permitem que o defer modifique err antes do retorno efetivo.
Erros comuns
- Chamar
recoverfora de umdefer:recoversó funciona se chamado diretamente dentro de uma função adiada. Fora disso, retornanile o panic continua. - Não usar retornos nomeados: se
errnão for nomeado, odefernão consegue modificar o valor de retorno facilmente. - Esquecer de verificar
r != nil: se não houver panic,recover()retornanil; atribuir isso aerrsobrescreveria um erro válido.
Outra forma de resolver
Poderíamos retornar um erro diretamente sem usar panic/recover, o que é mais idiomático em Go para erros esperados:
func safeDivide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("divisão por zero")
}
return a / b, nil
}
Saída esperada
10 / 2 = 5
10 / 0 = erro: divisão por zero