为什么将Regexp对象视为“虚假"?在Ruby中? [英] Why is a Regexp object considered to be "falsy" in Ruby?
问题描述
Ruby具有"真实性"和"虚假"的通用概念.
Ruby 确实具有两个特定的布尔对象类, TrueClass
和 FalseClass
,其中单例实例由特殊变量false
.
但是,真实性和虚假不仅限于这两个类的实例,概念是 universal ,并且适用于其中的每个对象红宝石.每个对象都是 truthy 或 falsy .规则很简单.特别是,只有两个对象是虚假的:
-
nil
,NilClass
和 的单例实例
-
false
,FalseClass
的单例实例
其他每个对象都是 truthy .这甚至包括在其他编程语言(例如
)中被视为 fassy 的对象这些规则是语言内置的,并且不是用户定义的.没有to_bool
隐式转换或类似的转换.
以下是 ISO Ruby语言规范 的引文:
6.6布尔值
一个对象分为 真实对象 或 虚假对象 .
只有 false 和 nil 是伪造的对象. false 是类
FalseClass
的唯一实例(请参见15.2.6), false-表达式对其进行评估(请参见11.5.4.8.3). nil 是NilClass
类的唯一实例(请参见15.2.4), nil-expression对其进行评估(请参见11.5.4.8.2).> 除 false 和 nil 以外的个对象被分类为真实对象. true 是类
TrueClass
(请参见15.2.5)的唯一实例, true-expression 对其进行评估(请参见11.5.4.8.3).>
it "considers a non-nil and non-boolean object in expression result as true" do if mock('x') 123 else 456 end.should == 123 end
根据这两个来源,我认为 Regexp
也是 truthy ,但是根据我的测试,它们不是:
if // then 'Regexps are truthy' else 'Regexps are falsy' end
#=> 'Regexps are falsy'
我在 YARV 2.7.0-preview1 , JRuby 9.2.8.0 .这三种实现方式彼此同意,不同意ISO Ruby语言规范和我对Ruby/Spec的解释.
更准确地说,作为评估Regexp
literals 结果的Regexp
对象是 falsy ,而Regexp
对象是某些其他表达式的结果是
r = //
if r then 'Regexps are truthy' else 'Regexps are falsy' end
#=> 'Regexps are truthy'
这是错误还是期望的行为?
这不是错误.发生的事情是Ruby正在重写代码,以便
if /foo/
whatever
end
有效地成为
if /foo/ =~ $_
whatever
end
如果您在普通脚本中运行此代码(而不使用-e
选项),则应该看到警告:
warning: regex literal in condition
在大多数情况下,这可能有些令人困惑,这就是发出警告的原因,但是对于使用-e
选项的一行来说可能很有用.例如,您可以使用
$ ruby -ne 'print if /foo/' filename
(print
的默认参数也是$_
.)
Ruby has a universal idea of "truthiness" and "falsiness".
Ruby does have two specific classes for Boolean objects, TrueClass
and FalseClass
, with singleton instances denoted by the special variables true
and false
, respectively.
However, truthiness and falsiness are not limited to instances of those two classes, the concept is universal and applies to every single object in Ruby. Every object is either truthy or falsy. The rules are very simple. In particular, only two objects are falsy:
nil
, the singleton instance ofNilClass
andfalse
, the singleton instance ofFalseClass
Every single other object is truthy. This includes even objects that are considered falsy in other programming languages, such as
These rules are built into the language and are not user-definable. There is no to_bool
implicit conversion or anything similar.
Here is a quote from the ISO Ruby Language Specification:
6.6 Boolean values
An object is classified into either a trueish object or a falseish object.
Only false and nil are falseish objects. false is the only instance of the class
FalseClass
(see 15.2.6), to which a false-expression evaluates (see 11.5.4.8.3). nil is the only instance of the classNilClass
(see 15.2.4), to which a nil-expression evaluates (see 11.5.4.8.2).Objects other than false and nil are classified into trueish objects. true is the only instance of the class
TrueClass
(see 15.2.5), to which a true-expression evaluates (see 11.5.4.8.3).
The executable Ruby/Spec seems to agree:
it "considers a non-nil and non-boolean object in expression result as true" do if mock('x') 123 else 456 end.should == 123 end
According to those two sources, I would assume that Regexp
s are also truthy, but according to my tests, they aren't:
if // then 'Regexps are truthy' else 'Regexps are falsy' end
#=> 'Regexps are falsy'
I tested this on YARV 2.7.0-preview1, TruffleRuby 19.2.0.1, and JRuby 9.2.8.0. All three implementations agree with each other and disagree with the ISO Ruby Language Specification and my interpretation of the Ruby/Spec.
More precisely, Regexp
objects that are the result of evaluating Regexp
literals are falsy, whereas Regexp
objects that are the result of some other expression are truthy:
r = //
if r then 'Regexps are truthy' else 'Regexps are falsy' end
#=> 'Regexps are truthy'
Is this a bug, or desired behavior?
This isn’t a bug. What is happening is Ruby is rewriting the code so that
if /foo/
whatever
end
effectively becomes
if /foo/ =~ $_
whatever
end
If you are running this code in a normal script (and not using the -e
option) then you should see a warning:
warning: regex literal in condition
This is probably somewhat confusing most of the time, which is why the warning is given, but can be useful for one lines using the -e
option. For example you can print all lines matching a given regexp from a file with
$ ruby -ne 'print if /foo/' filename
(The default argument for print
is $_
as well.)
这篇关于为什么将Regexp对象视为“虚假"?在Ruby中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!