3

||Ruby 1.8 不支持某些类型的重载(例如/ or&&/ and!/ not、 )有两个很好的理由?:

  • 如果不对语言进行非常广泛的更改,就无法使用 Ruby 中的方法实现短路语义。
  • Ruby 被硬编码为仅在布尔上下文中视为 false nilfalse

第一个原因不适用于!/not但第二个原因仍然适用。这不像您可以使用!while &&/||仍然是硬编码来引入您自己的类布尔对象。对于其他用途,已经~&/的互补运算符|

我可以想象有很多代码期望!objobj ? false : true, 和!!obj-同义,obj ? true : false我什至不确定代码应该如何处理在布尔上下文中评估为真但!非假的对象。

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

它有一些我想念的非常好的用途吗?

4

1 回答 1

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.

当然,正确的做法是向 Ruby 请求解析树并对其进行宏扩展。或者在 Ruby 解释器中使用调试钩子。有没有比这个更好的用例?

!顺便说一句,在翻译!=/!~旧方式时允许覆盖是不够的。For !((2+2).should == 5)to work在被调用#==之前不能引发异常。!但是,如果#==失败并且!没有运行,则执行将继续。我们将能够在块退出后将断言报告为失败,但代价是在第一次失败后执行测试。(除非我们在断言失败后打开 ruby​​ 调试钩子以查看下一个方法调用是否是!self,或类似的东西)

于 2010-07-30T14:12:22.333 回答