¿Cuándo usar os.Salir () y panic ()?

92

¿Alguien podría explicar las diferencias clave entre os.Exit()y panic()y cómo se utilizan en la práctica en Go?

Timur Fayzrakhmanov
fuente
11
Solo un comentario que, con suerte, ayudará en la lectura futura del código de Go: en muchos códigos de ejemplo, panicse usa para salir en caso de error, simplemente por el hecho de que es fácil de entender y elimina la importación de otros paquetes. ¡Esto no significa que sea una buena práctica o idiomática! . Es solo un dispositivo que ahorra espacio, por ejemplo, el código. Reserva IRL panicpara situaciones muy especiales.
Intermernet
1
Hm..bueno) especialmente la abreviatura "IRL" - es nueva para mí :) ¿Podría explicar cómo el pánico elimina la importación de paquetes?
Timur Fayzrakhmanov
4
panices un incorporado. Se recomienda (según las circunstancias) usar algo como os.Exit, log.Fataletc., que devolverá un código de error al sistema operativo (siempre recomendado si es posible). Todo esto implica la importación de un paquete y, por lo tanto, el código de ejemplo "desordenado". El código de ejemplo siempre debe tomarse solo para demostrar una solución a un problema específico. Puede haber otros problemas con el código, que lo hacen más complejo si se demuestra correctamente y, por lo tanto, restan valor a la explicación de la respuesta dada. YMMV.
Intermernet
1
Ok, ¡lo tengo!) Muchas gracias) Veo que hay otra abreviatura para mi vocabulario :)
Timur Fayzrakhmanov
2
NP, feliz de ayudar y de aumentar su léxico acrónimo :-)
Intermernet

Respuestas:

84

En primer lugar, siempre que tenga una pregunta sobre "cómo se usa en la práctica", una buena manera de comenzar es buscar el código fuente de Go (o cualquier base de código de Go suficientemente grande, en realidad) y los documentos del paquete para obtener respuestas.

Ahora, os.Exity panicson bastante diferentes. panicse utiliza cuando el programa, o su parte, ha alcanzado un estado irrecuperable.

Cuando panicse llama, incluso implícitamente para errores de tiempo de ejecución como indexar un segmento fuera de los límites o fallar una afirmación de tipo, detiene inmediatamente la ejecución de la función actual y comienza a desenrollar la pila de goroutine, ejecutando cualquier función diferida en el camino. Si ese desenrollado alcanza la parte superior de la pila de goroutine, el programa muere.

os.Exitse usa cuando necesita abortar el programa inmediatamente, sin posibilidad de recuperación o ejecutar una declaración de limpieza diferida, y también devuelve un código de error (que otros programas pueden usar para informar lo sucedido). Esto es útil en las pruebas, cuando ya sabe que después de que una de las pruebas falle, la otra también fallará, por lo que es mejor salir ahora. Esto también se puede usar cuando su programa ha hecho todo lo que tenía que hacer y ahora solo necesita salir, es decir, después de imprimir un mensaje de ayuda.

La mayoría de las veces no lo usará panic(debe devolver un erroren su lugar), y casi nunca lo necesitará os.Exitfuera de algunos casos en las pruebas y para la terminación rápida del programa.

Ainar-G
fuente
9
"Esto es útil en las pruebas, cuando ya sabes que después de que una prueba falla, la otra también fallará ..." Esto huele a un antipatrón de prueba de pruebas dependientes. En un conjunto de pruebas bien redactado, cada prueba es independiente; el resultado de una prueba determinada nunca debe determinar el resultado de ninguna otra prueba.
gotgenes
1
@gotgenes No necesariamente. Si tengo una prueba de que una determinada función devuelve una estructura que no es nula y esa prueba falla, entonces puedo esperar que todas las pruebas que examinan los valores de la estructura también fallarán. Es el código lo que depende, no las pruebas. (Dicho esto, no lo usaría exiten ese caso, solo esperaría una gran cantidad de afirmaciones fallidas).
David Moles
83

En primer lugar, os.Exit()se puede utilizar para salir del programa normalmente sin errores, y no entrar en pánico, así que esa es una distinción clave. Otra es que el pánico en algún lugar puede detectarse e ignorarse o registrarse mediante recover.

Pero si estamos hablando de un código de salida erróneo, digamos:

Úselo paniccuando algo salga terriblemente mal, probablemente un error del programador que debería haberse detectado antes de pasar a producción. Por eso imprime la pila.

Usa os.Exit(errorCode)o algo así si quieres:

  1. controlar el código de salida del programa con fines de secuencia de comandos.

  2. desea una salida ordenada en caso de un error esperado (por ejemplo, error de entrada del usuario).

Así que básicamente el pánico es para ti, un código de salida incorrecto es para tu usuario.

Not_a_Golfer
fuente
¡Gracias, muy útil!)
Timur Fayzrakhmanov
14
"Básicamente, el pánico es para ti, un código de salida incorrecto es para tu usuario". <-
Consejo
1
¿Podríamos decir que panic () está relacionado de alguna manera con la llamada habitual assert () en C simple? Bueno ... sé que siempre elimino las llamadas de confirmación antes de pasar a producción, solo las habilito cuando pruebo una nueva función. Lo que estoy diciendo es que la mayoría de las veces uso assert () para verificar invariantes que supongo deben ser verdaderas en mi código. ¿Ve el mismo uso para panic ()? :-)
yves Baumes
7

Las diferencias clave son:

  1. os.Exit omite la ejecución de la función diferida.
  2. Con os.Exit, puede especificar el código de salida.
  3. panicestá terminando mientras os.Exitque no. (Parece que otras respuestas no mencionan esto).

Si necesita ejecutar la función diferida, no tiene más remedio que panic. (Por otro lado, si desea omitir la ejecución de la función diferida, utilice os.Exit.)

Si una función no nula se define de tal manera:

  1. la función contiene muchas ramas
  2. todas las ramas terminan con returnopanic

Entonces no puede reemplazar paniccon, de lo os.Exitcontrario, el compilador se negará a compilar el programa, diciendo "falta el retorno al final de la función". (Go es muy tonto aquí, incluso log.Panicno termina una función).

En otras condiciones:

  1. Úselo paniccuando ocurra algo realmente cableado, por ejemplo, error de lógica de programación.
  2. Úselo os.Exitcuando desee una salida inmediata, con un código de salida especificado.
debilitado
fuente