Entendo o seguinte ponto em relação ao recover()
comportamento em Go.
recover()
Segue avaliação imediata, mas execução atrasada .
Então, se ele não for chamado dentro de uma função adiada (trecho de código 1), ele recover()
será avaliado naquele momento e, nesse ponto, ele ainda estará lá nil
e, portanto, nosso código entra em pânico.
Se for chamado dentro de uma função adiada, a chamada da função será registrada, mas recover()
será chamada depois que ocorrer panic
e será recuperada com sucesso.
package main
import "fmt"
func main() {
defer recover() // since not called inside a deferred func, it will not recover successfully
panic("This is a panic")
}
Agora, tendo isso em mente, escrevi o código abaixo.
import (
"fmt"
)
func main() {
defer func(){
customRecover()
}()
panic("This is a panic")
}
func customRecover(){
if r:= recover(); r!= nil{
fmt.Println("Custom Recovery for: ",r)
}
}
Pesquisei online o raciocínio e obtive a mesma resposta que
O valor de retorno de recover é nulo se qualquer uma das seguintes condições for atendida:
- o argumento do pânico era nulo;
- a goroutine não está em pânico;
- recover não foi chamado diretamente por uma função adiada.
Mas não consigo entender por que o segundo snippet não está funcionando?!?
Ela satisfaz todas as 3 condições estritamente falando. Há alguma ressalva que eu esteja esquecendo? Acho que a 3ª condição não é satisfeita porque ela não é chamada diretamente, mas por meio de uma chamada de função aninhada. Mas por que ela precisa estar dentro de deferred somente?
Como você declarou, a 3ª condição não é satisfeita. Recover não funcionará em uma função aninhada porque
panic
se propaga pela pilha de chamadas "para baixo" e no 2º snippet, arecover()
chamada nacustomRecover
função é "para cima" da perspectiva do pânico, então ela não "vê" o pânico.