2012-12-04 15 views
5
x = StandardError.new(:hello) 
y = StandardError.new(:hello) 
x == y # => true 
x === y # => true 

begin 
    raise x 
rescue x 
    puts "ok" # gets printed 
end 

begin 
    raise x 
rescue y 
    puts "ok" # doesn't get printed 
end 

Dlaczego nie drukuje się drugie "ok"? Nie mogę tego rozgryźć. Przeczytałem here, że ruby ​​używa operatora ===, aby dopasować wyjątki do klauzul ratunkowych, ale nie jest to prawdą.Co jest nie tak z tym przykładem ratunkowym?

Używam Ruby 1.9.3

EDIT: A więc wydaje się, że po zrobieniu raise x, x == y i x === y nie trzymać. Wydaje się, ponieważ x i yno longer have the same backtrace.

+0

Nie oznacza to, że „łapać StandardError i podklasy i umieścić między innymi w zmienna y”. 'y' nie jest interpretowane jako wartość (tak jak chcę), ale jako nazwa zmiennej. – Norswap

+0

Myślę, że jeśli próbujesz dopasować wzorce do tagów RFID, idiom "podnieś/złap" może nie być najłatwiejszym sposobem. Co powiesz na "case" lub dynamiczną wysyłkę za pomocą wzorców? –

+0

Aplikacja ma pewną logikę "niskiego poziomu", która komunikuje się z kartą. Tutaj są zgłaszane wyjątki. Powyżej tego jest wyższy poziom, logika aplikacyjna. Niektóre błędy zwracane przez znacznik są w rzeczywistości dość wysokim poziomem (takie rzeczy jak "plik już istnieje w tagu") i muszą wyświetlać kopie zapasowe z powrotem do użytkownika. Wyjątki wydają się najlepszą opcją. – Norswap

Odpowiedz

1

Chcę tylko dodać coś do tabeli: Kod OP sugeruje, że te dwa wyjątki są takie same, ale nie są one - ponadto chcę zilustrować co PO rozumie się:

Więc wydaje się, że po wykonaniu podbicia x, x == yi x === y już nie trzyma. Wydaje się, ponieważ x i y nie mają już tego samego śledzenia wstecznego.

x = StandardError.new(:hello) 
y = StandardError.new(:hello) 
class Object 
    def all_equals(o) 
    ops = [:==, :===, :eql?, :equal?] 
    Hash[ops.map(&:to_s).zip(ops.map {|s| send(s, o) })] 
    end 
end 

puts x.all_equals y # => {"=="=>true, "==="=>true, "eql?"=>false, "equal?"=>false} 

begin 
    raise x 
rescue 
    puts "ok" # gets printed 
end 

puts x.all_equals y # => {"=="=>false, "==="=>false, "eql?"=>false, "equal?"=>false} 
0

EDIT: Aby wyjaśnić ten problem dla przyszłych odpowiedziach, ponieważ myślę, że moja odpowiedź jest błędna, subtelność jest to, że x i yprzypadki zamiast klas i normalnie użyć klas w raise oświadczenie.


Jeżeli zamierzone zachowanie jest drukowanie na drugim ratunek The y nie załatwi. Podnosisz wyjątek klasy x i nie masz klauzuli ratunkowej, która obsłuży x. będzie można zobaczyć „ok” wydrukowane na drugim bloku, jeśli złapany StandardError, wspólną klasę bazową, choć:

begin 
    raise x 
rescue StandardError 
    puts "ok" 
end 

Odnośnie # ===, myślę, że problemem jest to, że podczas podnoszenia, masz do czynienia z instancją o numerze z x zamiast z x jako klasą.

+0

Wiem o tym, ale to nie jest moje pytanie. Moje pytanie brzmi: "dlaczego" rescue x' łapie 'x', podczas gdy' rescue y' does not? ". Nie wyjaśniłeś, dlaczego 'rescue x' łapie' x'. Masz również literówkę w swojej odpowiedzi, ponieważ nie "podniosłem wyjątku klasy" x "(" x "jest po prostu zmienną trzymającą wyjątek, który należy do klasy" StandardError "). Nie jestem pewien, co miałeś na myśli. – Norswap

+0

@Norswap: 'x' jest zmienną przechowującą odwołanie do klasy. Złapana rzecz jest instancją tej klasy. –

+0

Nie zawiera odniesienia do klasy. 'x.class => StandardError'. Jest to instancja klasy "StandardError". – Norswap

0

Wydaje się, że definicja jest ratunek:

[rescue [error_type [=> var],..] 

Ani x ani y jest stricly error_type. Są to instancje typu błędu. Nie sądzę, żebyś naprawdę uruchamiał poprawny kod tak, jak to robisz.

Jeśli prowadzisz:

begin 
    raise x 
rescue y.class 
    puts "ok" 
end 

Wtedy to będzie działać zgodnie z oczekiwaniami.

Należy również zauważyć, że na Ruby 1.8 ani x == y ani x === y nie zwraca true.

+0

Będę edytować pytanie, używam ruby ​​1.9.3 – Norswap

+0

@Norswap Ale nadal; Co dokładnie próbujesz zrobić?Zakładam, że po prostu się bawicie, ponieważ to, co w istocie robicie, jest jak mówienie "ratunek 1". To nie ma sensu. Powinieneś ratować klasy, a nie instancje. – Casper

+0

@Casper: Myślę, że kod jest poprawny (tzn. Jeśli kompiluje się, co robi). Czy to jasne, to inne pytanie. Ale nie sądzę, że jest to istotne dla tego pytania. –

2

Myślę, że to błąd, a raczej underspecyfikacja Rubiego 1.9. Zauważ, że Ruby 2.0 podnosi

TypeError: class or module required for rescue clause 

na liniach 8 i 14.

Należy pamiętać, że raise niekoniecznie robić to, co myślisz, że to robi, albo.Kiedy raise przedmiot, nie faktycznie podnieść że obiekt, możesz podnieść nowy przedmiot, który jest zbudowany z obiektu zdałeś zgodnie z tymi prostymi zasadami:

  • jeśli obiekt odpowiada exception zadzwoń exception na obiekcie i podniesienia wartości zwracanej
  • jeśli obiekt jest podklasą Exception, zadzwoń new i podniesienia wartości zwracanej
  • inaczej nie
  • również powiedzie się, jeśli wartość zwracana żadnej z powyższych metod nie jest instancją Exception

Więc jesteś nie faktycznie podniesienie x, jesteś podnoszenie x.exception. Według dokumentacji Exception#exceptionx.exception jest to jednak x.