2012-12-04 41 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 

爲什麼不打印第二個「ok」?我無法弄清楚。我讀過here,紅寶石使用===運算符來將異常與搶救子句進行匹配,但這顯然不是這種情況。這個救援例子有什麼問題?

我使用Ruby 1.9.3

編輯:所以它看起來像這樣做raise xx == yx === y不再持有後。這似乎是因爲xyno longer have the same backtrace

+0

不,這意味着「捕捉任何StandardError的和子類,並把實例放入變量y」。 'y'不被解釋爲一個值(正如我希望的那樣),而是作爲一個變量名。 – Norswap

+0

我想如果你想在RFID標籤上進行模式匹配,那麼'raise/catch'成語可能不是最清晰的路線。怎麼樣使用模式的'case'語句或動態分派? –

+0

該應用程序有一些與卡通信的「低級」邏輯。這是拋出異常的地方。以上是一些更高層次的應用邏輯。標籤返回的一些錯誤實際上是相當高的水平(比如「該文件已經存在於標籤中」),並且必須回滾給用戶。例外似乎是最好的選擇。 – Norswap

回答

1

我只是想添加一些表:OP代碼表明兩個例外是相同的,但他們都沒有 - 此外,我想說明什麼OP與意思:

所以看起來像做完x後,x == y和x === y不再成立。這似乎是因爲x和y不再具有相同的回溯。

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

編輯:澄清未來應對這個問題,因爲我覺得我的回答是不正確,這裏的微妙之處在於xy情況而不是,通常你會在使用類raise聲明。


如果預期的行爲是在第二救援打印時,y不會做的伎倆。您正在提出x類的例外情況,並且您沒有處理x的救援條款。你會看到「OK」字樣的第二塊,如果你抓到StandardError,共同的基類,雖然:

begin 
    raise x 
rescue StandardError 
    puts "ok" 
end 

關於#===,我認爲這個問題是,當你養,你處理實例x而不是x作爲一個類。

+0

我知道,但這不是我的問題。我的問題是「爲什麼'救援x'抓住'x'而'救援y'沒有?」。你沒有解釋爲什麼'救援x'抓住'x'。你的答案還有一個錯誤,因爲我沒有「引發類'x'的異常」('x'只是保存異常的變量,類是'StandardError')。我不確定你的意思。 – Norswap

+0

@Norswap:'x'是一個變量,持有對類的引用。被捕獲的東西是該類的一個實例。 –

+0

不,它不包含對課程的引用。 'x.class => StandardError'。它是類StandardError的一個實例。 – Norswap

0

看來,救援的定義是:

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

無論x也不y是stricly的error_type。它們是錯誤類型的實例。我認爲你並沒有像在那裏那樣運行有效的代碼。

如果你運行:

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

然後按預期它會工作。

另請注意,在Ruby 1.8上,x == yx === y都不返回true

+0

我會編輯的問題,我使用紅寶石1.9.3 – Norswap

+0

@Norswap但仍;你究竟想要做什麼?我假設你只是在玩耍,因爲你實質上就是在說'搶救1'。這沒有任何意義。你應該拯救班級,而不是實例。 – Casper

+0

@Casper:我認爲代碼是有效的(即,如果它編譯,它是這樣做的)。是否清楚是一個不同的問題。但我認爲這與問題無關。 –

2

我認爲這是一個錯誤,或者說是Ruby 1.9的一個不足之處。需要注意的是紅寶石2.0提出了一個

TypeError: class or module required for rescue clause 

在8號線和14

注意,raise並不一定做你認爲這樣做,無論是。當你raise一個對象,你實際上並沒有提高對象,你提出這是從您傳遞根據這些簡單的規則對象構造一個新對象

  • 如果對象響應exception ,在對象上調用exception如果對象是Exception一個子類提高的返回值
  • ,叫new,提高返回值
  • 否則失敗
  • 也未能如果上述任何方法的返回值不是Exception

一個實例,這樣,你是不是實際上提高x,你提出x.exception。但根據Exception#exceptionx.exception的文檔是x