为什么 Regexp 对象被认为是“虚假的"?在红宝石? [英] Why is a Regexp object considered to be "falsy" in Ruby?

查看:25
本文介绍了为什么 Regexp 对象被认为是“虚假的"?在红宝石?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Ruby 对truthiness"和falsiness"有一个普遍的想法.

Ruby确实有两个用于布尔对象的特定类,TrueClassFalseClass,单例实例分别由特殊变量 truefalse 表示.

然而,truthinessfalsiness 并不局限于这两个类的实例,这个概念是 universal 并且适用于红宝石.每个对象要么是真实的,要么是虚假的.规则非常简单.特别是,只有两个对象是假的:

每一个其他的对象都是真实的.这甚至包括在其他编程语言中被视为 falsy 的对象,例如

这些规则内置于语言中,用户无法定义.没有 to_bool 隐式转换或类似的东西.

这里引用了 ISO Ruby 语言规范:

<块引用>

6.6 布尔值

对象分为真实对象虚假对象.

只有 falsenil 是虚假对象.false 是类 FalseClass 的唯一实例(参见 15.2.6),false-expression 对其求值(参见 11.5.4.8.3).nilNilClass 类的唯一实例(参见 15.2.4),nil-expression 计算结果(参见 11.5.4.8.2).

falsenil 以外的对象被归类为 trueish 对象.true 是类 TrueClass 的唯一实例(见 15.2.5),true-expression 求值(见 11.5.4.8.3).

可执行的 Ruby/Spec 似乎同意:

<块引用>

它将表达式结果中的非零和非布尔对象视为真"如果模拟('x')123别的456结束.应该 == 123结尾

根据这两个来源,我假设 Regexps 也是 truthy,但根据我的测试,它们不是:

if//then 'Regexps are truthy' else 'Regexps are falsy' end#=>'正则表达式是假的'

我在 YARV 2.7.0-preview1TruffleRuby 19.2.0.1JRuby 9.2.8.0.所有三个实现都相互同意,但不同意 ISO Ruby 语言规范和我对 Ruby/Spec 的解释.

更准确地说,作为 Regexp literals 求值结果的 Regexp 对象是 falsy,而 >Regexp 对象是一些其他表达式的结果是truthy:

r =//if r then 'Regexps are truthy' else 'Regexps are falsy' end#=>'正则表达式是真实的'

这是一个错误,还是期望的行为?

解决方案

这不是错误.正在发生的事情是 Ruby 正在重写代码,以便

如果/foo/任何结尾

有效地变成

如果/foo/=~ $_任何结尾

如果您在普通脚本中运行此代码(而不是使用 -e 选项),那么您应该会看到一个警告:

警告:正则表达式文字在条件

这在大多数情况下可能有点令人困惑,这就是给出警告的原因,但对于使用 -e 选项的一行可能很有用.例如,您可以使用

打印文件中与给定正则表达式匹配的所有行

$ ruby​​ -ne 'print if/foo/' 文件名

(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:

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 class NilClass (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 Regexps 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 对象被认为是“虚假的"?在红宝石?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆