问题 如何创建一个在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或者玩==但没有成功。有任何想法吗?


12537
2018-01-21 18:30


起源

目前尚不清楚:什么是 Klass.method(values) 是吗 Object#method ?它将方法名称作为参数并返回一个Method,稍后您可以使用它 call。 - user1852994
相反,方法,想象一个“新”或构造函数 - Tiago Peczenyj


答案:


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

这是Ruby不面向对象的烦人案例之一。在OO,它 必须 一个物体可以模拟另一个物体(事实上,取决于你问的是谁,这就是它 定义 OO - 记住OO来自模拟),但是不可能构建一个模拟的对象 false

这是因为,在Ruby中,条件控制结构被烘焙到语言中并且不会转换为消息发送,而在其他OO语言中它们只是常规消息发送(或者至少转换为消息发送,就像 for 在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 至少让你有机会将你的对象转换为 Array。同样的道理 to_strto_intto_procto_float 等等。但没有相应的 to_bool 协议。


9
2018-01-22 00:01



谢谢。我试图这样做: github.com/peczenyj/Lazy-Bool  - 我选择Perl BTW。我会考虑你的例子并尝试做类似于Ruby的事情。 - Tiago Peczenyj


简短回答: 不要这样做

答案很长,在Ruby中有 只要 评价为假的两件事: false 和 nil。从字面上看,其他一切评价为真。

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


4
2018-01-21 19:18



在这种情况下,最好的选择是在布尔上下文中添加.to_bool来评估它,对吗? - Tiago Peczenyj
@TiagoPeczenyj an object who can act as a false based on some internal value  - >只需添加一个 false? 然后回答那个内部价值的方法 unless lol.false?。如果我没有弄错的话,这不是丑陋的,而是好的Ruby鸭子打字。 - user1852994
添加一个 false? 方法似乎有点奇怪,尤其是考虑 false.false? 将是一个未定义的方法。 - tadman
是的......听起来不错! - Tiago Peczenyj