Коли використовувати os.Exit () та паніку ()?


92

Хтось може пояснити ключові відмінності між os.Exit()і panic()і як вони використовуються на практиці в Go?


11
Просто коментар, який, сподіваємось, допоможе в майбутньому читанні коду Go: у багатьох прикладах код panicвикористовується для виходу з помилки, виключно завдяки тому, що його легко зрозуміти, і виключає імпорт будь-яких інших пакетів. Це не означає, що це хороша або ідіоматична практика! . Це просто пристрій для економії місця, наприклад код. Резерв IRL panicдля дуже особливих ситуацій.
Intermernet

1
Хм .. добре) особливо абревіатура "IRL" - для мене це нове :) Чи можете ви пояснити, як паніка виключає імпорт пакунків?
Тимур Файзрахманов

4
panicє вбудованим. Рекомендується ( в залежності від обставин) , щоб використовувати що - щось на зразок os.Exit, і log.Fatalт.д., який буде повертати код помилки в ОС (завжди рекомендується , якщо це можливо). Всі вони передбачають імпорт пакету і, таким чином, "захаращують" приклад коду. Приклад коду завжди слід брати лише для демонстрації рішення конкретної проблеми. Можуть бути й інші проблеми з кодом, які роблять код більш складним, якщо його належним чином продемонструвати, і, отже, погіршують пояснення даної відповіді. YMMV.
Intermernet

1
Гаразд, зрозумів!) Велике спасибі) Я бачу, що є ще одне скорочення мого словникового запасу :)
Тимур Файзрахманов

2
NP, радий допомогти та збільшити вашу абревіатурну лексику :-)
Intermernet

Відповіді:


84

Перш за все, щоразу, коли у вас виникає запитання "як це застосовується на практиці", хорошим способом почати є пошук у вихідному коді Go (або в будь-якій достатньо великій базі коду Go), а також у пакувальних документах для відповідей.

Зараз os.Exitі panicзовсім інші. panicвикористовується, коли програма або її частина перебуває у невиправному стані.

Коли panicйого викликають, зокрема неявно для помилок під час виконання, таких як індексація зрізу поза межами або невдале твердження типу, він негайно зупиняє виконання поточної функції і починає розмотувати стек програми, запускаючи будь-які відкладені функції по дорозі. Якщо це розмотування досягає вершини стека програми, програма вмирає.

os.Exitвикористовується, коли вам потрібно негайно перервати програму , без можливості відновлення або запуску відкладеного оператора очищення, а також повернути код помилки (який інші програми можуть використовувати для повідомлення про те, що сталося). Це корисно в тестах, коли ви вже знаєте, що після того, як цей тест не вдасться, інший теж не зможе, тому ви можете просто вийти зараз. Це також можна використовувати, коли ваша програма зробила все, що їй потрібно було зробити, а тепер просто потрібно вийти, тобто після друку довідкового повідомлення.

Більшу частину часу ви не будете використовувати panic(вам слід повернути errorзамість цього), і вам майже ніколи не знадобляться os.Exitдеякі випадки в тестах і для швидкого припинення програми.


9
"Це корисно в тестах, коли ви вже знаєте, що після того, як один тест не вдасться, інший теж не зможе ..." Це пахне тестовим анти-шаблоном залежних тестів. У добре написаному наборі тестів кожен тест є незалежним; результат будь-якого даного тесту ніколи не повинен визначати результат будь-якого іншого тесту.
gotgenes

1
@gotgenes Не обов'язково. Якщо у мене є тест, що певна функція повертає ненульову структуру, і цей тест не вдається, то я можу очікувати, що всі тести, які досліджують значення структури, теж не зможуть. Це код, який залежить, а не тести. (Тим не менше, я б не використовував exitу цьому випадку, я б просто очікував великого стопки невдалих тверджень.)
Девід

83

Перш за все, os.Exit()його можна використовувати для нормального виходу з програми без помилок, і без паніки, тому це одна ключова відмінність. Інша ситуація полягає в тому, що паніку десь можна вловити, проігнорувати або зареєструвати, використовуючи recover.

Але якщо ми говоримо про помилковий код виходу, скажімо:

Використовуйте, panicколи щось іде жахливо не так, ймовірно, помилка програміста, яку слід було вловити перед початком виробництва. Ось чому він друкує стек.

Використовуйте os.Exit(errorCode)або щось подібне, якщо хочете:

  1. контролювати код виходу програми для цілей сценаріїв.

  2. хочуть упорядкованого виходу з очікуваної помилки (наприклад, помилка введення користувачем).

Отже, в основному паніка для вас, поганий код виходу для вашого користувача.


Дякую дуже корисно!)
Тимур Файзрахманов

14
"Отже, в основному паніка для вас, поганий код виходу для вашого користувача". <-
Чудова

1
Чи можемо ми сказати, що panic () якось пов’язаний із звичайним викликом assert () у простому C? Ну .. я знаю, що завжди видаляю затверджуючий дзвінок перед тим, як перейти на виробництво, я вмикаю їх лише під час тестування нової функції. Я хочу сказати, що більшу частину часу я використовую assert () для перевірки інваріантів, які, мабуть, мають виконуватися в моєму коді. Ви бачите те саме використання паніки ()? :-)
yves Baumes

7

Ключові відмінності:

  1. os.Exit пропускає виконання відкладеної функції.
  2. За допомогою os.Exitви можете вказати код виходу.
  3. panicприпиняється, а os.Exitні. (Здається, інші відповіді про це не згадують.)

Якщо вам потрібно виконати відкладену функцію, у вас немає іншого вибору, крім panic. (З іншого боку, якщо ви хочете пропустити виконання відкладеної функції, використовуйте os.Exit.)

Якщо функція, що не є порожньою, визначена таким чином:

  1. функція містить багато гілок
  2. всі філії припиняються за допомогою returnабоpanic

Тоді ви не можете замінити panicна os.Exitінше, компілятор відмовиться компілювати програму, сказавши "відсутність повернення в кінці функції". (Go тут дуже тупий, навіть log.Panicне припиняє функцію.)

За інших умов:

  1. Використовуйте, panicколи трапляється щось дійсно дротове, наприклад, помилка логіки програмування.
  2. Використовуйте, os.Exitколи потрібно негайний вихід, із зазначеним кодом виходу.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.