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

时间:2013-01-21 18:30:07

标签: 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或使用==但没有成功。任何想法?

2 个答案:

答案 0 :(得分:11)

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

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

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

each

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 }) 的对象。

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

答案 1 :(得分:4)

简短回答:不要这样做

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

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