如何创建一个在Ruby中扮演假的对象

我想做这个

lol = Klass.new(values) unless lol print "false" end lol.other_method # it is not nil or false, it is a Klass instance! 

但在这种情况下,lol不是零或假,而是一个基于某种内在价值可以作为假的对象。 我有这个选择

 lol = Klass.new(values) unless lol.to_bool print "false" end 

但它是丑陋的恕我直言。

我在想扩展FalseClass或者玩==但没有成功。 有任何想法吗?

不幸的是,这是不可能的。

这是Ruby不面向对象的烦人案例之一。 在OO中,一个对象必须能够模拟另一个对象(实际上,取决于你询问的对象,这是OO的定义 – 记住OO来自模拟),但是不可能构建一个对象模拟false

这是因为,在Ruby中,条件控制结构被烘焙到语言中并且不会转换为消息发送,而在其他OO语言中它们只是常规消息发送(或者至少转换为消息发送,就像在Ruby中翻译一样)进入each )。 例如,在Smalltalk中,Booleans实际上是使用Lambda Calculus所知的Booleans的Church编码实现的,并且转换为Ruby它们看起来有点像这样:

 class FalseClass def if(&block) # do nothing end def if_then_else(then_lambda, else_lambda) else_lambda.() end def not true end def and(&block) self end def or(&block) block.() end end 

TrueClass只是镜像:

 class TrueClass def if(&block) block.() end def if_then_else(then_lambda, else_lambda) then_lambda.() end def not false end def and(&block) block.() end def or(&block) self end end 

然后,而不是像

 if 2 < 3 then foo end if 2 < 3 then bar else baz end 

你将会拥有

 (2 < 3).if { foo } (2 < 3).if_then_else(-> { bar }, -> { baz }) # using the new keyword arguments in Ruby 2.0, it almost reads like Smalltalk: class FalseClass def if(then: -> {}, else: -> {}) else.() end end class TrueClass def if(then: -> {}, else: -> {}) then.() end end (2 < 3).if(then: -> { bar }, else: { baz }) 

这样,您可以通过实现相应的方法轻松创建一个模拟false的对象。

在其他情况下,某些对象确实绝对必须是特定类的实例而不只是说正确的协议,Ruby提供了一个逃生舱。 例如,如果一个方法确实需要一个Array作为参数,那么它将首先尝试调用to_ary ,至少让你有机会将你的对象转换为一个Arrayto_strto_intto_procto_float等也是to_float 。但是没有等效的to_bool协议。

简短的回答: 不要这样做

长期的答案是,在Ruby中只有两个评估为false的东西: falsenil 。 从字面上看,其他一切评价为真。

许多应用程序依赖于此行为,如果您以某种方式设法更改此操作,可能会出现故障。 这就像将1定义为偶数一样。 这会引起问题。