为什么Ruby 1.9允许覆盖! !=!〜?

时间:2010-07-30 09:34:34

标签: ruby ruby-1.9

有两个很好的理由说明为什么Ruby 1.8不支持某些类型的重载,例如|| / or&& / and! / not?:

  • 如果没有对语言进行大量更改,Ruby中的方法无法实现短路语义。
  • Ruby被硬编码为仅在布尔上下文中将nilfalse视为false。

第一个原因不适用于! / not,但第二个原因仍然适用。这并不像你只使用!引入自己类型的布尔类对象,而&& / ||仍然是硬编码的。对于其他用途,已经存在具有~ / &的互补运算符|

我可以想象有很多代码期望!objobj ? false : true同义,而!!objobj ? true : false同义 - 我甚至不确定代码是怎么回事处理在布尔上下文中求值为true的对象,但!处理为非假的对象。

Ruby似乎不打算引入对其他错误值的支持。 Ruby stdlib中的任何内容似乎都不会覆盖!,所以我没有找到任何示例。

它是否有一些非常好的用途我错过了?

1 个答案:

答案 0 :(得分:1)

自回复。到目前为止我找到了一个合理的用法。我可以通过几行来破解它在1.9.2中的工作:

describe "Mathematics" do
  it "2 + 2 != 5" do
    (2+2).should != 5
  end
end

在1.9.2 Ruby之前,这转换为:

describe "Mathematics" do
  it "2 + 2 != 5" do
    ((2+2).should == 5) ? false : true
  end
end

但是当返回值被抛弃时,我们没有办法区分== 5!= 5之间没有问过Ruby的块的解析树。 PositiveOperatorMatcher#==(5)只会引发ExpectationNotMetError异常,那就是它。似乎should !~ /pattern/should !be_something等也可以发挥作用。

这比(2+2).should_not == 5有所改善,但并不是很大。并且没有办法进一步破解它以获得(2+2).should be_even or be_odd

之类的东西

当然,正确的做法是asking Ruby for parse tree and macro-expanding that。或者在Ruby解释器中使用调试钩子。是否有比这更好的用例?

顺便说一下,在翻译旧版! / !=时,允许覆盖!~是不够的。要使!((2+2).should == 5)工作#==,在调用!之前无法引发异常。但是如果#==失败并且!没有运行,则执行将继续执行。我们将能够在块退出后将断言报告为失败,但是在第一次失败后执行测试的成本。 (除非我们在断言失败后打开ruby调试挂钩,看看下一个方法调用是!self,还是类似的东西)