不幸的是,这是不可能的。
这是 Ruby 不是面向对象的那些烦人的情况之一。在 OO 中,一个对象必须可以模拟另一个对象(实际上,这取决于您问谁,这就是 OO 的定义——记住 OO 来自模拟),但不可能构建一个对象模拟false
.
这是因为,在 Ruby 中,条件控制结构被嵌入到语言中并且不会转换为消息发送,而在其他 OO 语言中它们只是常规消息发送(或至少转换为消息发送,就像for
在 Ruby 中转换为each
)。例如,在 Smalltalk 中,布尔值实际上是使用您从 Lambda 演算中知道的布尔值的 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 提供了一个逃生口。例如,如果一个方法确实需要 aArray
作为参数,那么它会首先尝试调用to_ary
to 至少给你一个机会将你的对象转换为Array
. to_str
, to_int
,to_proc
等也是如此to_float
。但没有等效的to_bool
协议。