En muchos lugares vas a leer que Go no tiene excepciones. Esto no es cierto.
En Go si hay excepciones, la diferencia es que se llaman panics
.
La razón es que desde la popularidad de Java, las excepciones ya no se usan para situaciones excepciones sino para cualquier error, y todo el tiempo hay errores.
Los autores de Go querían dar a entender que las excepciones deberían ser excepcionales y por eso eligieron la palabra panic
para representarlas.
El gran problema de las excepciones es que rompen el flujo del programa y no es posible razonar sobre lo que pasa en el flujo cuando se produce una excepción, su funcionamiento es muy parecido al famoso goto
que tanto se desaconseja. Rompe la estructura de control y puede saltar a cualquier parte por lo que leer el código es más difícil y en consecuencia mantenerlo.
El gran objetivo de Go es crear un lenguaje simple, fácil de leer y mantener, por lo tanto las excepciones en Go no deberían ser abusadas pero en ocasiones no hay alternativa y es mejor capturar y manejar la excepción, aunque sea de manera genérica.
Lo recomendable en Go es tener funciones cortas, y lo normal es ver un par de veces por función:
...
if err != nil {
return nil, err
}
...
Esto es verboso pero ayuda muchísimo a razonar sobre el código, por lo que ayuda a producir código de mejor calidad.
Pero, ahora veamos cómo capturar excepciones al estilo try-catch. Supongamos el siguiente código:
package main
func raiseException() {
panic("exception!")
}
func main() {
raiseException()
}
Este código siempre lanza una excepción. Para capturar la excepción se debe usar defer
+ recover
:
package main
import "fmt"
func raiseException() {
panic("exception!")
}
func catch(f func()) {
defer func() {
if r := recover(); r != nil {
fmt.Println("exception caught:", r)
}
}()
f()
}
func main() {
catch(func() {
raiseException()
})
}
De esta manera podemos capturar y manejar las excepciones en partes del código que no controlamos.