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使用===
运算符来匹配rescue子句的异常,但表面上并非如此。
我正在使用Ruby 1.9.3
编辑:所以在raise x
,x == y
和x === y
不再成功之后似乎就是这样。这似乎是因为x
和y
no longer have the same backtrace。
答案 0 :(得分:2)
我认为这是一个错误,或者说是Ruby 1.9的不足之处。请注意,Ruby 2.0引发了
TypeError: class or module required for rescue clause
在第8和14行。
请注意,raise
不一定按照您的想法行事。当你raise
一个对象时,实际上并没有提出那个对象,你提出了一个 new 对象,它是根据你传递的对象构造的。规则:
exception
,请在对象上调用exception
并提高返回值Exception
的子类,请调用new
并提高返回值Exception
的实例,则所以,你 实际上正在筹集x
,你正在筹集x.exception
。尽管如此,根据Exception#exception
x.exception
的文档是x
。
答案 1 :(得分: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}
答案 2 :(得分:0)
编辑:为了澄清未来回复的问题,因为我认为我的回答不正确,这里的细微之处在于x
和y
是实例< / em>而不是 classes ,通常你会在raise
语句中使用类。
如果预期的行为是在第二次救援时进行打印,y
将无法解决问题。您正在引发类x
的异常,并且您没有可以处理x
的救援子句。如果你抓住StandardError
(公共基类),你会看到为第二个块打印“ok”:
begin
raise x
rescue StandardError
puts "ok"
end
关于#===,我认为问题在于,当你加注时,你正在处理x
而不是x
的实例作为一个类。
答案 3 :(得分:0)
似乎救援的定义是:
[rescue [error_type [=> var],..]
x
和y
都不是error_type
。它们是错误类型的实例。我不认为你真正按照你在那里的方式运行有效的代码。
如果你跑:
begin
raise x
rescue y.class
puts "ok"
end
然后它将按预期工作。
另请注意,在Ruby 1.8上,x == y
和x === y
都不会返回true
。