Quand utiliser os.Exit () et panic ()?

92

Quelqu'un pourrait-il expliquer les principales différences entre os.Exit()et panic()et comment ils sont utilisés dans la pratique dans Go?

Timur Fayzrakhmanov
la source
11
Juste un commentaire qui, espérons-le, aidera à la lecture future du code Go: dans de nombreux exemples de code, il panicest utilisé pour quitter en cas d'erreur, uniquement en raison du fait qu'il est facile à comprendre et élimine l'importation de tout autre package. Cela ne veut pas dire que c'est une bonne pratique ou une pratique idiomatique! . C'est juste un appareil peu encombrant par exemple de code. Réserve IRL panicpour des situations très particulières.
Intermernet
1
Hm .. bon) en particulier l'abréviation "IRL" - c'est nouveau pour moi :) Pourriez-vous expliquer comment la panique élimine l'importation de paquets?
Timur Fayzrakhmanov
4
panicest un builtin. Il est recommandé (selon les circonstances) d'utiliser quelque chose comme os.Exit, log.Fataletc., qui renverra un code d'erreur au système d'exploitation (toujours recommandé si possible). Tout cela implique l'importation d'un package, et donc un exemple de code "encombré". Un exemple de code ne doit toujours être utilisé que pour démontrer une solution à un problème spécifique. Il peut y avoir d'autres problèmes avec le code, qui rendent le code plus complexe s'il est correctement démontré, et donc nuisent à l'explication de la réponse donnée. YMMV.
Intermernet
1
Ok, compris!) Un grand merci) Je vois qu'il y a encore une autre abréviation pour mon vocabulaire :)
Timur Fayzrakhmanov
2
NP, heureux de vous aider et d'augmenter votre lexique acronyme :-)
Intermernet

Réponses:

84

Tout d'abord, chaque fois que vous avez une question «comment il est utilisé en pratique», une bonne façon de commencer est de rechercher le code source de Go (ou toute autre base de code Go assez grande, vraiment), et la documentation du package pour obtenir des réponses.

Maintenant, os.Exitet panicsont assez différents. panicest utilisé lorsque le programme, ou sa partie, a atteint un état irrécupérable.

Lorsqu'il panicest appelé, y compris implicitement pour des erreurs d'exécution telles que l'indexation d'une tranche hors limites ou l'échec d'une assertion de type, il arrête immédiatement l'exécution de la fonction actuelle et commence à dérouler la pile de la goroutine, exécutant toutes les fonctions différées en cours de route. Si ce déroulement atteint le sommet de la pile de la goroutine, le programme meurt.

os.Exitest utilisé lorsque vous devez abandonner le programme immédiatement, sans possibilité de récupération ou d'exécuter une instruction de nettoyage différé, et également renvoyer un code d'erreur (que d'autres programmes peuvent utiliser pour signaler ce qui s'est passé). Ceci est utile dans les tests, lorsque vous savez déjà qu'après l'échec de ce test, l'autre échouera également, vous pouvez donc aussi bien quitter maintenant. Cela peut également être utilisé lorsque votre programme a fait tout ce qu'il devait faire et qu'il n'a plus qu'à quitter, c'est-à-dire après avoir imprimé un message d'aide.

La plupart du temps, vous n'utiliserez pas panic(vous devriez retourner un à la errorplace), et vous n'en aurez presque jamais besoin en os.Exitdehors de certains cas dans les tests et pour l'arrêt rapide du programme.

Ainar-G
la source
9
«Ceci est utile dans les tests, quand vous savez déjà qu'après l'échec de ce test, l'autre échouera également…» Cela sent un anti-modèle de test de tests dépendants. Dans une suite de tests bien écrite, chaque test est indépendant; le résultat d'un test donné ne devrait jamais déterminer le résultat d'un autre test.
gotgenes
1
@gotgenes Pas nécessairement. Si j'ai un test qu'une certaine fonction renvoie une structure non-nil et que ce test échoue, alors je peux m'attendre à ce que tous les tests qui examinent les valeurs de la structure échouent également. C'est le code qui dépend, pas les tests. (Cela dit, je n'utiliserais pas exitdans ce cas, je m'attendrais juste à une grosse pile d'assertions ratées.)
David Moles
83

Tout d'abord, os.Exit()peut être utilisé pour quitter le programme normalement sans erreur, et pas de panique, c'est donc une distinction clé. Un autre est que la panique quelque part peut être capturée et ignorée ou enregistrée en utilisant recover.

Mais si nous parlons d'un code de sortie erroné, disons:

À utiliser paniclorsque quelque chose ne va pas du tout, probablement une erreur de programmeur qui aurait dû être détectée avant de passer en production. C'est pourquoi il imprime la pile.

Utilisez os.Exit(errorCode)ou quelque chose comme ça si vous voulez:

  1. contrôler le code de sortie du programme à des fins de script.

  2. veulent une sortie ordonnée sur une erreur attendue (par exemple, une erreur d'entrée utilisateur).

Donc, fondamentalement, la panique est pour vous, un mauvais code de sortie est pour votre utilisateur.

Not_a_Golfer
la source
Merci très utile!)
Timur Fayzrakhmanov
14
"Donc, fondamentalement, la panique est pour vous, un mauvais code de sortie est pour votre utilisateur." <-
Astuce géniale
1
Pourrions-nous dire que panic () est en quelque sorte lié à l'appel assert () habituel en C brut? Eh bien ... je sais que je supprime toujours les appels d'assertions avant de passer à la production, je les active uniquement lors du test d'une nouvelle fonctionnalité. Ce que je dis, c'est que la plupart du temps, j'utilise assert () pour vérifier les invariants qui, je suppose, doivent être vérifiés dans mon code. Voyez-vous la même utilisation pour panic ()? :-)
yves Baumes
7

Les principales différences sont:

  1. os.Exit ignore l'exécution de la fonction différée.
  2. Avec os.Exit, vous pouvez spécifier le code de sortie.
  3. panicse termine alors que os.Exitne l'est pas. (Il semble que d'autres réponses ne mentionnent pas cela.)

Si vous devez exécuter la fonction différée, vous n'avez pas d'autre choix que panic. (D'un autre côté, si vous voulez ignorer l'exécution de la fonction différée, utilisez os.Exit.)

Si une fonction non vide est définie de cette manière:

  1. la fonction contient beaucoup de branches
  2. toutes les succursales se terminent par returnoupanic

Ensuite, vous ne pouvez pas remplacer panicpar os.Exitsinon le compilateur refusera de compiler le programme en disant "retour manquant à la fin de la fonction". (Go est très stupide ici, log.Panicne met même pas fin à une fonction.)

Dans d'autres conditions:

  1. À utiliser paniclorsque quelque chose de vraiment câblé se produit, par exemple une erreur de logique de programmation.
  2. À utiliser os.Exitlorsque vous souhaitez une sortie immédiate, avec le code de sortie spécifié.
faible
la source