Ruby'də "Exception => e" yazmaq üçün nə üçün pis bir stil var?

Ryan Davis Ruby QuickRef deyir (şərh vermədən):

Istisna saxlamayın. HƏR. ya da sizə vuracağam.

Niyə olmasın? Nə etməliyəm?

812
06 апр. Aprel ayının 06-da John tərəfindən təyin olundu 2012-04-06 22:17 '12 at 10:17 pm 2012-04-06 22:17
@ 6 cavablar

Tl; DR : ümumi catch detection əvəzinə StandardError istifadə edin. Orijinal istisna yenidən qaldırıldıqda (məsələn, yalnız bir istisnanın qeydiyyatı üçün qənaət edərkən), Exception qənaət edilməsi yaxşıdır.


Exception Ruby istisna hiyerarşisinin köküdür, belə ki, LoadError SyntaxError , LoadErrorInterrupt kimi alt siniflər daxil olmaqla, hər şeyi xilas LoadError .

Interrupt qaçmaq istifadəçi proqramdan çıxmaq üçün CTRL C istifadə etməyə icazə vermir.

Rescue SignalException , proqramın siqnallara düzgün cavab verməsinə icazə vermir. Bu kill -9 istisna olmaqla, bu, qüsursuz olacaq.

SyntaxError , uğursuz olan eval səssizcə edəcək.

Bütün bunlar bu proqramı işlətmək və CTRL C seçmək və ya kill :

 loop do begin sleep 1 eval "djsakru3924r9eiuorwju3498 += 5u84fior8u8t4ruyf8ihiure" rescue Exception puts "I refuse to fail or be stopped!" end end 

İstisnadan xilas olmaq hətta default deyil. İcra

 begin # iceberg! rescue # lifeboats end 

istisna olaraq saxlamır, StandardError saxlayır. Adətən StandardError dəyərindən daha konkret bir şey müəyyənləşdirməlisiniz, ancaq İstisnadan qənaət onu daraltmak yerine genişləndirir və fəlakətli nəticələrə səbəb ola bilər və səhvlərlə işləmək çətinləşir.


StandardError saxlamaq istədiyiniz bir vəziyyətiniz varsa və istisna olmaqla bir dəyişənə ehtiyacınız varsa, bu formu istifadə edə bilərsiniz:

 begin # iceberg! rescue => e # lifeboats end 

buna bərabərdir:

 begin # iceberg! rescue StandardError => e # lifeboats end 

İstisnadan xilas olmaq üçün həssas yol olduğu bir neçə ümumi hallardan biri gündəmə / hesabat verməkdir, bu halda istisnanı dərhal yenidən yaratmalısınız:

 begin # iceberg? rescue Exception => e # do some logging raise e # not enough lifeboats ;) end 
1261
06 апр. Andrew Marshall tərəfindən verilmiş cavab Apr 06 2012-04-06 22:38 '12 at 10:38 pm 2012-04-06 22:38

Həqiqi qayda: istisnalar atmayın. Sitat gətirən müəllifin obyektivliyi sual altındadır, buna görə bitdiyini sübut edir

ya da sizə vuracağam

Əlbəttə ki, siqnalların (default olaraq) istisnalara gətirib çıxarması və ümumiyyətlə, uzun proseslər bir siqnal ilə bitdiyini nəzərə alsaq, istisna istisna siqnal istisnaları ilə bitmir, bu proqramı çox dayandıra bilər. Buna görə də bunu etməyin:

 #! /usr/bin/ruby while true do begin line = STDIN.gets # heavy processing rescue Exception => e puts "caught exception #{e}! ohnoes!" end end 

Xeyr, həqiqətən bunu etməyin. Hətta işləməyinə əmin olmaq üçün bu işi də etməyin.

Ancaq, bir stream server olduğunu və bütün istisnaların olmadıqlarını bildirək:

  • ignore (default)
  • thread.abort_on_exception = true dayandırın ( thread.abort_on_exception = true deyirsəniz nə olur).

Sonra bu əlaqənin emal axını üçün idealdır:

 begin # do stuff rescue Exception => e myLogger.error("uncaught #{e} exception while handling connection: #{e.message}") myLogger.error("Stack trace: #{backtrace.map {|l| " #{l}\n"}.join}") end 

Yuxarıda, Ruby istisna işleyicisinin default versiyasına aiddir, bununla da proqramınızı öldürməyin üstünlüyü. Rails bu istək işçisi ilə bunu edir.

border=0

Əsas mövzu istisnalar. Arxa axınları onları ala bilməyəcək, buna görə onları tutmaq üçün heç bir mənası yoxdur.

Bu, bir şey yanlış gedir zaman proqram sadəcə dayandırmaq istəmirəm bir istehsal mühitində xüsusilə faydalıdır. Daha sonra zirzəmilərinizi yığışdırmalarınıza daxil edə və kodunuzu zəng zəncirindən və daha zərif şəkildə müəyyən bir istisna ilə həll etmək üçün əlavə edə bilərsiniz.

Eyni təsiri olan bir başqa Ruby idiotu da var:

 a = do_something rescue "something else" 

Bu xəttdə, əgər do_something bir istisna do_something , Ruby tərəfindən tutulur, atılır və "something else" təyin olunur.

Bir qayda olaraq, bunu etməyin, istisna olmaqla, narahat olmayın ki, bildiyiniz hallarda. Bir nümunə:

 debugger rescue nil 

debugger funksiyası kodunuzda bir kəsmə nöqtəsi qurmaq üçün olduqca yaxşı bir yoldur, lakin hata ayıklayıcısı və Rails xaricində işləyərsə istisna atılır. İndi, nəzəri olaraq, proqramınızdakı ayıklama kodunu tərk etməməlisiniz (pff! Heç kim bunu etmir!), Ancaq bir müddətdən sonra orada saxlamağınızı istəməyinizi istəməyəcəksiniz, ancaq hər dəfə hata ayıklayıcısını çalıştırmamalısınız.

Qeyd:

  • İstisnaları tutan başqalarının proqramını çalıştırırsanız və onları (yəni yuxarıda göstərilən kodu) görmürsənsə, aşağıdakı adımları edin:

    • Linux üzərində bir qabıqda pgrep ruby və ya ps | grep ruby daxil edin ps | grep ruby , sizin intruder PID tapmaq və kill -9 <PID> .
    • Windows'da, tapşırıq meneceri ( CTRL - SHIFT - ESC ) istifadə edin, "proseslər" sekmesine keçin, əməliyyatınızı tapın, sağa vurun və "İşlemi Sonlandır" ı seçin.
  • Əgər istisna olmaqla, bu istisna blokları tərəfindən nədən ibarətdirsə, onu əsas xəttin üstünə yerləşdirmək mümkün yollardan biridir:

     %W/INT QUIT TERM/.each { |sig| trap sig,"SYSTEM_DEFAULT" } 

    Bu, proqramın normal tamamlama siqnallarına cavab verməsini, istisna işləyicilərini kənarlaşdırmadan, dərhal dayandırmağa imkan verir. Beləliklə, məlumatların itirilməsinə və ya buna səbəb ola bilər. Ehtiyatlı olun!

  • Bunu etmək lazımdırsa:

     begin do_something rescue Exception => e critical_cleanup raise end 

    həqiqətən bunu edə bilərsiniz:

     begin do_something ensure critical_cleanup end 

    İkinci vəziyyətdə, istisnaların seçilməsindən asılı olmayaraq critical cleanup hər dəfə çağırılacaqdır.

76
07 апр. Cavab Maykl Slade tərəfindən Apr 07 verildi 2012-04-07 08:30 '12 'də saat 08:30' da

Gəlin avtomobilindəyəm (Rubin çalışır). Siz yaxın zamanda havada bir yeniləmə sistemi ( eval istifadə edən) ilə yeni bir sükan çarxı quraşdırdınız, amma proqramçılardan biri sözdizimini eval bilmirdiniz.

Körpüyə gedirsən, anladınız ki, qəfəsə doğru bir az gedərkən, sola dönürsən.

 def turn_left self.turn left: end 

oops! Bu yəqin ki, yaxşı deyil, lakin Ruby bir SyntaxError qaldırır.

Avtomobil dərhal dayanmalıdır - sağ?

Nope

 begin #... eval self.steering_wheel #... rescue Exception => e self.beep self.log "Caught #{e}.", :warn self.log "Logged Error - Continuing Process.", :info end 

bip səsi

Uyarı: Sabit SyntaxError istisna.

Məlumat: Qeydə alınan səhv davamlı bir prosesdir.

Bir şeyin yanlış olduğuna diqqət yetirirsiniz və təcili fasilələrə toxunursunuz ( ^C : Interrupt )

bip səsi

Xəbərdarlıq: Sabit müdaxilə fasiləsi.

Məlumat: Qeydə alınan səhv davamlı bir prosesdir.

Bəli, kömək etmədi. Siz dəmir SignalException , buna görə parkı parka qoyun ( kill : SignalException ).

bip səsi

Xəbərdarlıq: SignalException istisna.

Məlumat: Qeydə alınan səhv davamlı bir prosesdir.

Sonuncu saniyədə düymələri çıxarın ( kill -9 ) və avtomobil dayanarsa, sükan çarxına (hava yastığı proqramı zərif şəkildə dayandırmadığınız üçün şişirə bilməzsiniz) - avtomobilin arxasındakı kompüter çökdü onun qarşısında oturacaq. Koksiyanın tam hüquqlu bir qutusu qiymətli kağızlarla şişelenmişdir. Arxa məhsullar ezilmiş və onların əksəriyyəti yumurta sarısı və süd ilə örtülmüşdür. Avtomobil ciddi təmir və təmizliyə ehtiyac duyur. (Məlumatların itirilməsi)

Sığorta ehtiyatınız var (yedekləyin). Oh, bəli, çünki hava yastıqları şişməyib, ehtimal ki, əziyyət çəkirsiniz.


Ancaq gözləyin! Orada Daha çox rescue Exception => e istifadəsi səbəbləri səbəblərdən rescue Exception => e !

Avtomobil olduğunuzu və avtomobilin təhlükəsiz əyləc anını aşarsa hava yastığının şişirdilməsindən əmin olun.

  begin # do driving stuff rescue Exception => e self.airbags.inflate if self.exceeding_safe_stopping_momentum? raise end 

Qaydaya bir istisna: istisnanı təkrar artırdığınız halda istisna edə bilərsiniz. Beləliklə, ən yaxşı qayda istisna halını Exception və həmişə səhvini yenidən qaldırmaqdır.

Lakin xilas əlavə Ruby kimi bir dildə unutmaq asandır və bir az quru hiss edərək problemi təkrar artırmadan əvvəl qurtuluşa dair bir ifadə qoydu. Və raise haqqında ifadəni unutmaq istəmirsiniz. Və əgər, bu səhv tapmaq üçün uğurlar uğursuz.

Xoşbəxtlikdən, Ruby zəhmli, yalnız kodun işləməsini təmin edən sözü ensure istifadə edə bilərsiniz. Sözündən asılı olmayaraq, sözü yerinə yetirəcəkdir - bir istisna seçildiyi təqdirdə tək istisna - əgər dünya başa çatarsa (və ya digər qeyri-mümkün hadisələr).

  begin # do driving stuff ensure self.airbags.inflate if self.exceeding_safe_stopping_momentum? end 

Boom! Və bu kod hər halda işləməlidir. rescue Exception => e istifadəsinin yeganə səbəbi rescue Exception => e istisna etmək üçün istəsəniz və ya kodu istisna olmaqla icra edilməsini istəyirsən. Və səhvini yenidən qaldırmayı unutmayın. Hər dəfə.

Qeyd @Niall qeyd etdiyimiz kimi, həmişə işləyir. Bu yaxşıdır, çünki bəzən proqramınız sizə yalançı ola bilər və problemlər yaranarsa da istisnalar atmamalıdır. Hava yastıqlarının şişirilməsi kimi mühüm vəzifələrlə, bunun nə olursa olsun olmasını təmin etmək lazımdır. Bunun səbəbi, maşının dayandığı hər dəfə yoxlanılması bir istisna deyil, yaxşı bir fikirdir. Hava yastıqlarının şişirilməsi çox proqramlaşdırma kontekstində qeyri-adi bir işin bir hissəsidir, baxmayaraq ki, ən çox təmizləyici işlərdə həqiqətən də çox rast gəlinir.


Tl; DR

rescue Exception => e (və istisnayı yenidən qaldırmaq) - rescue Exception => e etməyin və ya körpüdən çıxa bilərsiniz.

51
01 февр. Cavab Ben Aubin tərəfindən verilir 01 fevral. 2016-02-01 02:55 '16 'da 2:55' də 2016-02-01 02:55 'də

Çünki bütün istisnaları düzəldir. Proqramınızın hər hansı birindən qurtarma ehtimalı çox azdır.

Yalnız bərpa etmək üçün necə bildiyiniz istisnalara sahib olmalısan. Xüsusi bir istisna gözləmirsinizsə, onu işləməyin, yüksək səslə (jurnala məlumat yazmaq), sonra da qeydləri tanılayın və kodu düzəlt.

İstisnaları yudumlamaq pis deyil, bunu etməyin.

44
06 апр. Sergio Tulentsev tərəfindən verilən cavab 06 Aprel. 2012-04-06 22:21 '12 at 10:21 pm 2012-04-06 22:21

Qaydaların hər hansı bir istisnasını tutmamalı olduğunuz xüsusi bir vəziyyət nədir, necə idarə edəcəyinizi bilmirsiniz. Bunu necə idarə etməyinizi bilmirsinizsə, sistemin digər hissəsini tutmaq və işləməyə imkan vermək həmişə yaxşıdır.

9
07 апр. Cavab Russell Borogove tərəfindən verilir 07 Apr 2012-04-07 02:54 '12 at 2:54 2012-04-07 02:54

Məsələn, əgər səhvən metodun adını göstərsəniz, səhvləri sizdən də gizlədəcək:

 def my_fun "my_fun" end begin # you mistypped my_fun to my_func my_func # my_func() rescue Exception # rescued NameError (or NoMethodError if you called method with parenthesis) end 
1
25 марта '17 в 12:11 2017-03-25 12:11 cavab 25 mart '17 'də 12:11 2017-03-25-25 12:11' də fangxing verilir