Jör*_*tag 15 ruby regex boolean yarv jruby
Ruby有“的普遍想法感实性 ”和“ falsiness ”。
Ruby 确实有两个特定的布尔对象类,TrueClass和FalseClass,其中单例实例分别由特殊变量true和表示false。
但是,真实性和虚假性不仅限于这两个类的实例,该概念是通用的,适用于Ruby中的每个对象。每个对象都是真实的或虚假的。规则很简单。特别是,只有两个对象是虚假的:
nil,的一个实例,NilClass以及false,的单例实例 FalseClass每个其他对象都是真实的。这甚至包括在其他编程语言中被认为是虚假的对象,例如
这些规则是语言内置的,并且不是用户定义的。没有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表达式将对其进行评估(请参见11.5.4.8.3)。
Run Code Online (Sandbox Code Playgroud)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
根据这两个来源,我认为Regexps也是真实的,但根据我的测试,它们不是:
if // then 'Regexps are truthy' else 'Regexps are falsy' end
#=> 'Regexps are falsy'
Run Code Online (Sandbox Code Playgroud)
我在YARV 2.7.0-preview1,TruffleRuby 19.2.0.1和JRuby 9.2.8.0上进行了测试。这三种实现都彼此同意,不同意ISO Ruby语言规范和我对Ruby / Spec的解释。
更准确地说,Regexp作为评估Regexp 文字的结果的对象是虚假的,而Regexp作为其他表达式的结果的对象是真实的:
r = //
if r then 'Regexps are truthy' else 'Regexps are falsy' end
#=> 'Regexps are truthy'
Run Code Online (Sandbox Code Playgroud)
这是错误还是期望的行为?
这不是一个错误。正在发生的事情是 Ruby 正在重写代码,以便
if /foo/
whatever
end
Run Code Online (Sandbox Code Playgroud)
有效地变成
if /foo/ =~ $_
whatever
end
Run Code Online (Sandbox Code Playgroud)
如果您在普通脚本中运行此代码(并且不使用该-e选项),那么您应该看到警告:
if /foo/
whatever
end
Run Code Online (Sandbox Code Playgroud)
大多数时候这可能有点令人困惑,这就是给出警告的原因,但对于使用该-e选项的一行可能很有用。例如,您可以从文件中打印与给定正则表达式匹配的所有行
$ ruby -ne 'print if /foo/' filename
Run Code Online (Sandbox Code Playgroud)
( for 的默认参数print也是$_如此。)
这是(据我所知)ruby 语言的一个未记录的特性的结果,这个规范最好地解释了这一点:
it "matches against $_ (last input) in a conditional if no explicit matchee provided" do
-> {
eval <<-EOR
$_ = nil
(true if /foo/).should_not == true
$_ = "foo"
(true if /foo/).should == true
EOR
}.should complain(/regex literal in condition/)
end
Run Code Online (Sandbox Code Playgroud)
您通常可以将其$_视为“读取的最后一个字符串gets”
更令人困惑的是,$_(连同$-)不是全局变量;它有本地范围。
当 ruby 脚本启动时,$_ == nil.
所以,代码:
// ? 'Regexps are truthy' : 'Regexps are falsey'
Run Code Online (Sandbox Code Playgroud)
被解释为:
(// =~ nil) ? 'Regexps are truthy' : 'Regexps are falsey'
Run Code Online (Sandbox Code Playgroud)
...返回falsey。
另一方面,对于非文字正则表达式(例如r = //或Regexp.new('')),这种特殊解释不适用。
//是真实的;就像 ruby 中除niland之外的所有其他对象一样false。
除非直接在命令行上运行 ruby 脚本(即使用-e标志),否则 ruby 解析器将显示针对此类用法的警告:
警告:条件中的正则表达式文字
您可以在脚本中使用此行为,例如:
puts "Do you want to play again?"
gets
# (user enters e.g. 'Yes' or 'No')
/y/i ? play_again : back_to_menu
Run Code Online (Sandbox Code Playgroud)
...但将局部变量分配给结果gets并显式地针对该值执行正则表达式检查会更正常。
我不知道使用空正则表达式执行此检查的任何用例,尤其是在定义为文字值时。您强调的结果确实会让大多数 ruby 开发人员措手不及。