variable log how golang fmt exceptions error code exception-handling error-handling go

exception handling - log - Atrapando el pánico en Golang



how to return an error in golang (6)

Con el siguiente código, si no se da un argumento de archivo, se genera un ataque de pánico en la línea 9 panic: runtime error: index out of range como se esperaba.

¿Cómo puedo ''atrapar'' este pánico y manejarlo directamente cuando le paso algo ( os.Args[1] ) que causa pánico? Al igual que try / catch en PHP o try / except en Python.

He tenido una búsqueda aquí en StackOverflow pero no he encontrado nada que responda a esto como tal.

package main import ( "fmt" "os" ) func main() { file, err := os.Open(os.Args[1]) if err != nil { fmt.Println("Could not open file") } fmt.Printf("%s", file) }


Primero: no querrías hacer esto. El manejo de errores al estilo Try-catch no implica el manejo de errores. En Go, debe verificar len(os.Args) primero y acceder al elemento 1 solo si está presente.

Para los raros casos en los que necesita atrapar el pánico (¡y su caso no es uno de ellos!) Utilice el defer en combinación con la recover . Ver http://golang.org/doc/effective_go.html#recover


Go no es Python, debe verificar correctamente los argumentos antes de usarlo:

func main() { if len(os.Args) != 2 { fmt.Printf("usage: %s [filename]/n", os.Args[0]) os.Exit(1) } file, err := os.Open(os.Args[1]) if err != nil { log.Fatal(err) } fmt.Printf("%s", file) }


Tenga en cuenta que el tratamiento de recuperación de un error de Ejecución de pánico (como el intento de indexar una matriz fuera del desencadenante de límites) puede cambiar con ir 1.7 después de la edición 14965

Ver CL 21214 y su prueba :

tiempo de ejecución: hacer que los valores de pánico de error de ejecución implementen la interfaz de Error

Haga que los pánicos de ejecución implementen un error según los pánicos en tiempo de ejecución (especificaciones) , en lugar de pánico con cadenas.

Cuando recupere un error de pánico, podrá hacer:

if _, ok := recovered.(runtime.Error); !ok {

Esto todavía se está evaluando, y como Dave Cheney . menciona:

No sé lo que las personas están haciendo actualmente, pero desde mi POV esto se ha roto durante mucho tiempo y nadie se ha quejado, por lo que dependen explícitamente del comportamiento roto, o a nadie le importa. De cualquier manera, creo que es una buena idea evitar hacer este cambio.


Un programa de pánico se puede recuperar con la función de recover() incorporada:

La función de recover permite que un programa administre el comportamiento de un goroutine en pánico. Supongamos que una función G difiere una función D que llama a recover y se produce un pánico en una función en la misma rutina en la que G está ejecutando. Cuando el funcionamiento de las funciones diferidas llega a D , el valor de retorno de la llamada de recover de D será el valor pasado a la llamada de panic . Si D regresa normalmente, sin iniciar un nuevo panic , la secuencia de pánico se detiene. En ese caso, el estado de las funciones llamadas entre G y la llamada al panic se descarta y se reanuda la ejecución normal. Cualquier función diferida por G antes D se ejecuta y la ejecución de G finaliza volviendo a su llamador.

El valor de retorno de la recuperación es nulo si se cumple alguna de las siguientes condiciones:

  • panic argumento del panic fue nil ;
  • el goroutine no está entrando en pánico;
  • recover no fue llamado directamente por una función diferida.

Aquí hay un ejemplo de cómo usar esto:

// access buf[i] and return an error if that fails. func PanicExample(buf []int, i int) (x int, err error) { defer func() { // recover from panic if one occured. Set err to nil otherwise. if (recover() != nil) { err = errors.New("array index out of bounds") } }() x = buf[i] }

Tenga en cuenta que la mayoría de las veces, el pánico no es la solución correcta. El paradigma Go es verificar los errores de forma explícita. Un programa solo debe entrar en pánico si las circunstancias bajo las cuales se produce el pánico no ocurren durante la ejecución ordinaria del programa. Por ejemplo, no ser capaz de abrir un archivo es algo que puede suceder y no debe causar pánico mientras se está quedando sin memoria, vale la pena entrar en pánico. Sin embargo, este mecanismo existe para poder atrapar incluso estos casos y quizás cerrar con gracia.


Algunos paquetes oficiales de Golang usan panic / defer + recover como throw / catch , pero solo cuando necesitan desenrollar una gran pila de llamadas. En el paquete json de Golang, usar pánico / aplazar + recuperar como lanzar / atrapar es la solución más elegante.

de http://blog.golang.org/defer-panic-and-recover

Para ver un ejemplo real de pánico y recuperación, consulte el paquete json de la biblioteca estándar Go. Descodifica datos codificados en JSON con un conjunto de funciones recursivas. Cuando se encuentra JSON malformado, el analizador llama a pánico para desenrollar la pila a la llamada de función de nivel superior, que se recupera del pánico y devuelve un valor de error apropiado (consulte los métodos ''error'' y ''unmarshal'' del tipo decodeState en decodificación .ir).

Busque d.error( en http://golang.org/src/encoding/json/decode.go

En su ejemplo, la solución "idiomática" es verificar los parámetros antes de usarlos, como han señalado otras soluciones.

Pero, si quiere / necesito capturar algo , puede hacer lo siguiente:

package main import ( "fmt" "os" ) func main() { defer func() { //catch or finally if err := recover(); err != nil { //catch fmt.Fprintf(os.Stderr, "Exception: %v/n", err) os.Exit(1) } }() file, err := os.Open(os.Args[1]) if err != nil { fmt.Println("Could not open file") } fmt.Printf("%s", file) }


Tuve que atrapar el pánico en un caso de prueba. Me redirigieron aquí.

func.go

var errUnexpectedClose = errors.New("Unexpected Close") func closeTransaction(a bool) { if a == true { panic(errUnexpectedClose) } }

func_test.go

func TestExpectedPanic() { got := panicValue(func() { closeTransaction(true) }) a, ok := got.(error) if a != errUnexpectedClose || !ok { t.Error("Expected ", errUnexpectedClose.Error()) } } func panicValue(fn func()) (recovered interface{}) { defer func() { recovered = recover() }() fn() return }

Utilizado desde https://github.com/golang/go/commit/e4f1d9cf2e948eb0f0bb91d7c253ab61dfff3a59 (ref de VonC)