Bir CATCH bloğundaki İstisna ve Arıza arasındaki farkı [RAKU]


9

Bir Arızanın bir CATCH bloğu tarafından ele alınabileceğini biliyoruz.

Aşağıdaki örnekte 'AdHoc' Hatası (diğer altta) oluşturuyoruz ve İstisna'yı bir CATCH bloğunda (alt-altta) ele alıyoruz

sub my-sub {
    try {
        CATCH {
            when X::AdHoc { say 'AdHoc Exception handled here'; .resume }
            default {say 'Other Exception'; .resume}
        }

        my $b = other-sub();

        $b.so ?? $b.say !! 'This was a Failure'.say;
    }
}

sub other-sub { fail 'Failure_X' }

my-sub();

Çıktı aşağıdaki gibidir:

AdHoc Exception handled here
This was a Failure

Sorum şu: İki vaka arasında ayrım yapmak için CATCH bloğundaki Arıza ile "normal" bir İstisna arasında nasıl ayrım yapabiliriz?

Yanıtlar:


12

Arasındaki ilişki Failureve Exceptionbir olduğunu Failurebir sahiptir Exception- söylemek olduğunu, onun devletin parçası olarak istisna nesnesini tutar. Bunun gibi bir şey:

class Failure {
    has Exception $.exception;
    # ...
}

Bir Failure"patladığında" bunu Exceptioniçinde olanı fırlatarak yapar . Böylece, CATCHbloğa ulaşan şey Exceptionnesnedir ve çevreye geri bir bağlantı yoktur Failure. (Aslında, belirli bir Exceptionnesne prensipte birçok kişi tarafından tutulabilir Failure.)

Bu nedenle, bunu tespit etmenin doğrudan bir yolu yoktur. Tasarım açısından bakıldığında, muhtemelen olmamalı ve probleminizi çözmek için farklı bir yol bulmalısınız. A Failuresadece bir istisnanın atılmasını ertelemenin ve bir değer olarak muamele görmesine izin vermenin bir yoludur; altta yatan sorunun doğasının değişmesi amaçlanmamıştır, çünkü kontrol akışının derhal aktarılması yerine bir değer olarak iletilir. Ne yazık ki, asıl hedef soruda belirtilmedi; kontrol istisnalarına bakmak yararlı olabilir, ancak aksi takdirde çözmeye çalıştığınız temel sorun hakkında başka bir soru yayınlayabilirsiniz. Muhtemelen daha iyi bir yol var.

Bütünlüğü sağlamak için, orada dikkat edeceğiz olan biri olduğunu tespit edebileceğimiz anlamına dolaylı yolları Exceptionbir tarafından atıldı Failure. Örneğin .backtrace, istisna nesnesini alır ve üst çerçevenin paketine bakarsanız, nesnenin aşağıdakilerden geldiğini belirlemek mümkündür Failure:

sub foo() { fail X::AdHoc.new(message => "foo") }
try {
    foo();
    CATCH {
        note do { no fatal; .backtrace[0].code.package ~~ Failure };
        .resume
    }
}

Ancak, bu büyük ölçüde kolayca değişebilecek uygulama ayrıntılarına bağlıdır, bu yüzden ona güvenmem.


Sadece işleri açıklığa kavuşturmak için, amacım sadece istisnalar için (CATCH bloğunda) ele almak. Bir Arıza durumunda, hiçbir şey olmamış gibi devam etmek ve kodun geri kalanının (CATCH dışında) Arızayı işlemesine izin vermek istiyorum. Örneğimde, döndürülen Arızanın içerilen İstisna'yı tetiklemesini beklemiyordum! Tek yaptığım sonucu $ b'de almak ve bir Bool olarak kontrol etmek. Benim görüşüme göre, Arıza'nın “kullanımı” ve dolayısıyla CATCH bloğunun tetiklenmesi anlamına gelmez! Bunun yerine, CATCH her zaman Arızada bulunan İstisnayı ele alıyor gibi görünüyor!
jakar

Ayrıca, örneğinizde, bir Arızayı tespit etmenin dolaylı yolu hakkında, döndürülen Bool (Arıza Türünü akıllı kontrol ederek) "False" değerine sahiptir. Ama bunun "Doğru" olmasını bekliyordum! Bir şey mi kaçırdım???
jakar

1
@jakar Bir tryblok pragmayı ima eder use fatal, yani Failureblokta yapılan bir çağrıdan döndürülen herhangi bir çağrı hemen istisnaya dönüştürülür. Sadece kullanmayın try; a CATCHRaku herhangi bir blok içinde gidebilirsiniz (yani sadece düzeyinde olsun sub). Alternatif olarak, bloğunuzun no fatalüst kısmına yazın try.
Jonathan Worthington

Peki ya ikinci yorumum?
jakar

1
Örneği çalıştırarak Trueyerel olarak aldığım Rakudo versiyonunda baskılar verdim . Sizinkinde değilse, bu sadece bunu yapmanın kırılganlığıyla ilgili noktayı kanıtlar.
Jonathan Worthington

6

Sargıyı çıkarmanız tryyeterlidir:

sub my-sub {

#    try {              <--- remove this line...

        CATCH {
            when X::AdHoc { say 'AdHoc Exception handled here'; .resume }
            default {say 'Other Exception'; .resume}
        }

        my $b = other-sub();

        $b.so ?? $b.say !! 'This was a Failure'.say;

#    }                  <--- ...and this one

}

sub other-sub { fail 'Failure_X' }

my-sub();

Sen kullandın try. A trybirkaç şey yapar, ancak buradaki ilgili şey Raku'ya Failurekapsamındaki herhangi bir durumu derhal istisnalara tanıtmasını söyler - ki bunu istemediğinizi söylersiniz . Yani en basit çözüm bunu yapmayı bırakmaktır.


Bu cevap, jnthn'ın açıklamasının bir kısmını ayrıntılı olarak tekrarlar (özellikle cevabının altında yazdığı yorumlara bakın). Ancak tüm okuyucuların bu yönü fark edeceğinden / anlayacağından ikna olmadım ve jnthn'ın cevabına ilişkin bir veya iki yorumun yardımcı olacağını düşünmedim, bu yüzden bu cevap.

Bunu herhangi bir upvotes'tan faydalanmamamı sağlamak için bir topluluk cevabı olarak yazdım çünkü açıkçası bunu garanti etmiyor. Yeterli downvotes alırsa, sadece sileriz.

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.