73/100 Dias de Golang - Panic, Defer e Recover
Table of Contents
#
Panic, Defer e Recover
Estava buscando temas e coisas ainda não abordadas. E vi que ainda não falei especificamente sobre Panic, Defer e Recover. Hoje vamos falar mais osbre o Defer
.
#
Defer
O defer
é muito simples, ele agenda um execução para logo antes do return da atual função. Veja esse exemplo:
func deferExemplo() {
fmt.Println("Início")
defer fmt.Println("Fim")
fmt.Println("Meio")
}
A saída será:
Início
Meio
Fim
Uma coisa interessante é que podemos ter vários defer
e eles usam o padrão LIFO (last in, first out)
func deferExemplo() {
fmt.Println("Início")
defer fmt.Println("Primeiro defer")
defer fmt.Println("Segundo defer")
defer fmt.Println("Terceiro defer")
fmt.Println("Meio")
}
Início
Meio
Terceiro defer
Segundo defer
Primeiro defer
Em Go, podemos dar nome aos valores de retorno diretamente na assinatura da função. Isso faz com que esses valores sejam tratados como variáveis declaráveis e acessíveis dentro da função, sem precisar declará-los novamente. Nessa função de exemplo o return
já sabe que deve retornar o resultado
func soma(a, b int) (resultado int) {
resultado = a + b
return
}
E esse comportamento permite com que consigamos alterar o returno do defer
:
func teste() (res int) {
defer func() {
res += 1
}()
return 10
}
Esse ponto é muito importante: O defer
é executado depois da avaliação do return, mas antes da saída real da função. Veja essa função: aqui o valor 1 já foi “salvo”; o defer não afeta o retorno
func exemplo() int {
res := 1
defer func() {
res++
}()
return res
}
Então temos que o defer
é executado após o return ser preparado, mas antes da função realmente retornar o valor.
O Defer é executado mesmo no caso de panic
da função:
func exemplo() {
defer fmt.Println("isso será impresso mesmo com panic")
panic("erro fatal")
}
Podemos dar um recover dentro de um defer
func exemplo() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recuperado de:", r)
}
}()
panic("algo deu errado")
}
func main() {
exemplo()
print("Tudo certo...")
}
A saída:
Recuperado de: algo deu errado
Tudo certo...
O uso do defer está muito associado com a liberação de recursos. Exemplo: fechar um arquivo mesmo se ocorrer erro no meio
file, _ := os.Open("arquivo.txt")
defer file.Close()
Ou quando estamos usando um Mutex:
var mu sync.Mutex
func acesso() {
mu.Lock()
defer mu.Unlock()
}