Raising Exceptions vs Throwing Exceptions arasındaki fark nedir?


168

Ruby'nin iki farklı istisna mekanizması vardır: Atma / Yakalama ve Kaldırma / Kurtarma.

Neden iki tane var?

Birini diğerini değil, ne zaman kullanmalısınız?


“İç içe döngülerden çıkmak” birçok programlama dilinde yaygın bir ihtiyaçtır. Ayrıca gotoiçinde C / C ++ @docwhat sözü var gibi Java gelmiştir mola etiketlenmiş ve devam . (Python'un da bunun için reddedilmiş bir teklifi var .)
Franklin Yu

Yanıtlar:


104

Bence http://hasno.info/ruby-gotchas-and-caveats farkın iyi bir açıklaması var:

yakalama / fırlatma yükseltme / kurtarma ile aynı değildir. catch / throw, blokları belirli bir sembol için bir catch'in tanımlandığı bir noktaya hızlı bir şekilde geri çıkmanıza izin verir, yükseltme kurtarma, Exception nesnesini içeren gerçek istisna işleme şeyleridir.


1
Bilmek meraklı ... Bunu bir iPad'den okumak, bu yüzden onları 1.9'da test edemezsiniz, ancak bu gotcha'ların bazıları son yakut sürümlerinde artık geçerli değil mi?
Denis de Bernardy

12
Ayrıca bilmeye değer: raiseçok pahalıdır. throwdeğil. Bir döngüden çıkmak için throwkullanmayı düşünün goto.
12:34 de docwhat

4
@Denis Hangi markalara atıfta bulunuyorsunuz?
docwhat

1
Bağlantı koptu!
morhook

Performans farkı hakkında daha fazla bilgi edinmek için yakut yakalama ve verimliliğe bakın .
Franklin Yu

110
  • raise, fail, rescueVe ensuresap hataları olarak da bilinen istisnalar
  • throwve catchvardır kontrol akışı

Diğer dillerin aksine, Ruby'nin atış ve yakalama istisnaları için kullanılmaz. Bunun yerine, daha fazla çalışmaya ihtiyaç duyulmadığında uygulamayı erken sona erdirmenin bir yolunu sunarlar. (Grimm, 2011)

Bir whiledöngü gibi tek bir kontrol akışı seviyesini sonlandırmak basit bir işlemle yapılabilir return. İç içe geçmiş bir döngü gibi birçok kontrol akışı düzeyini sonlandırmak ile yapılabilir throw.

Yükseltme ve kurtarma istisna mekanizması, işler ters gittiğinde yürütmeyi terk etmek için harika olsa da, normal işleme sırasında derinden iç içe bazı yapılardan atlamak bazen güzeldir. Yakalama ve atma işte burada devreye giriyor. (Thomas ve Av, 2001)

Referanslar

  1. Grimm, Avdi. "Fırlat, Yakala, Kaldır, Kurtar ... Çok Şaşkınım!" RubyLearning Blogu. Np, 11 Temmuz 2011. Web. 1 Ocak 2012. http://rubylearning.com/blog/2011/07/12/throw-catch-raise-rescue--im-so-confused/ .
  2. Thomas, Dave ve Andrew Hunt. "Ruby programlama." : Pragmatik Programcı Kılavuzu. Np, 2001. Web. 29 Eylül 2015. http://ruby-doc.com/docs/ProgrammingRuby/html/tut_exceptions.html .

2
Avdi yok değil o podcast sesleri benziyor.
hrdwdmrbl

2
Ruby Learning bağlantısı çalışmıyor. İşte farklılıkları tartışan başka bir blog yazısı: danielchangnyc.github.io/blog/2013/10/23/throw-raise
Dennis

Komik, rubylearning.com Avdi'nin makalesinin hala orada olduğunu düşünüyor . Sanırım şeyleri SO'ya kopyalıyoruz, bu yüzden kaybolmayacak!
Jared Beck

21

https://coderwall.com/p/lhkkug/don-t-confuse-ruby-s-throw-statement-with-raise , geliştirebileceğimden şüphe ettiğim mükemmel bir açıklama sunuyor. Özetlemek gerekirse, blog gönderisinden bazı kod örneklerini gittikçe nickleme:

  1. raise/ rescue, diğer dillerden (veya Python's / ) aşina olduğunuz throw/ catchconstruct'a en yakın analoglardır . Bir hata durumuyla karşılaşırsanız ve bunu başka bir dilde yaparsanız , Ruby'de yapmalısınız .raiseexceptthrowraise

  2. Ruby throw/ catchçalıştırmayı kırmanıza ve catch(beğen raise/ yap rescue) gibi bir şey bulmak için yığına tırmanmanıza izin verir , ancak gerçekten hata koşulları için değildir. Nadiren kullanılmalıdır ve sadece "karşılık catchgeleni bulana kadar yığını yukarı taşı " davranışı, yazdığınız bir algoritma için mantıklı olduğunda, ancak throwbir hataya karşılık gelen gibi düşünmenin mantıklı olmadığı durumlarda durum.

    Ruby'de yakalama ve fırlatma ne için kullanılır? throw/ catchconstruct'ın güzel kullanımları hakkında bazı önerilerde bulunur .

Aralarındaki somut davranışsal farklılıklar şunları içerir:

  • rescue FooFooalt sınıfları dahil olmak üzere örnekleri kurtaracak Foo. catch(foo)sadece aynı nesneyiFoo yakalar . Sadece catchörneklerini yakalamak için bir sınıf adı iletmekle kalmaz, aynı zamanda eşitlik karşılaştırmaları bile yapmaz. Örneğin

    catch("foo") do
      throw "foo"
    end

    size UncaughtThrowError: uncaught throw "foo"(veya ArgumentError2.2'den önceki Ruby sürümlerinde)

  • Birden fazla kurtarma maddesi listelenebilir ...

    begin
      do_something_error_prone
    rescue AParticularKindOfError
      # Insert heroism here.
    rescue
      write_to_error_log
      raise
    end

    birden çok catches'in yuvalanması gerekirken ...

    catch :foo do
      catch :bar do
        do_something_that_can_throw_foo_or_bar
      end
    end
  • Çıplak rescue, rescue StandardErrordeyimsel bir yapıya eşdeğerdir ve bir deyimdir. Bir "çıplak catch", catch() {throw :foo}asla hiçbir şeyi yakalamaz ve kullanılmamalıdır.


İyi bir açıklama ama soruya yalvarır, neden dünya üzerinde yakut = başka bir dile atmak isterler? ve sonra atmayı da dahil et ama! = diğer dillerde at. Orjinal mantıklarını orada göremiyorum
wired00

@ wired00 (Shrug.) Bugün diğer popüler dillere kıyasla oldukça eksantrik göründüğüne katılıyorum.
Mark Amery

2
@ wired00: 1960'larda yapılandırılmış hata işleme ile yapılan ilk deneylerden bu yana "istisna" olarak adlandırıldı, buna modern istisna işleme biçimini icat eden seminal makalelerde "yükseltme" denir, buna Ruby için ana ilham kaynaklarından bazıları olan Lisps ve Smalltalks'ta bir istisna "yükseltmek" ve buna "programlama" konseptinden önce bile var olan donanımda bir istisna "yükseltmek" veya "kesinti" denir. dil "vardı. Soru şu olmalıdır: diğer diller neden bunu değiştirdi?
Jörg W Mittag

@MarkAmery: Bu "diğer popüler diller" in çoğunun Ruby'den daha genç veya en azından çağdaş olduğunu unutmayın. Öyleyse soru şu olmalıdır: diğer diller neden Ruby'yi (ve Smalltalk ve Lisp ve donanım ve literatür) takip etmedi.
Jörg W Mittag

@ JörgWMittag İlginç - biraz tarihsel araştırma yapmam için bana ilham verdin. C ++, Ruby gelmeden yıllar önce bir istisna "atma" fikrine sahipti ve english.stackexchange.com/a/449209/73974 terimi aslında 70'lere geri dönüyor ... bu yüzden Ruby'yi hala eleştiriyoruz yerleşik terminolojiyi kullanmak ve bunu tamamen farklı bir şey ifade etmek için kullanmak.
Mark Amery
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.