我从一个bash shell运行以下命令:
echo 'hello world' | ruby -ne 'puts $_ if /hello/'
Run Code Online (Sandbox Code Playgroud)
我一开始以为这是一个拼写错误,但hello world
令人惊讶的输出.
我打算输入:
echo 'hello world' | ruby -ne 'puts $_ if /hello/ === $_'
Run Code Online (Sandbox Code Playgroud)
任何人都可以给出解释,或指向文档,为什么我们得到这种隐式比较$_
?
我还要注意:
echo 'hello world' | ruby -ne 'puts $_ if /test/'
Run Code Online (Sandbox Code Playgroud)
不输出任何东西.
Ruby 解析器对于条件中的正则表达式文字有一个特殊情况。通常(即不使用e
,n
或p
命令行选项)此代码:
if /foo/\n puts "TRUE!"\nend\n
Run Code Online (Sandbox Code Playgroud)\n\n产生:
\n\nif /foo/\n puts "TRUE!"\nend\n
Run Code Online (Sandbox Code Playgroud)\n\n分配与正则表达式匹配的内容$_
,如下所示:
$_ = \'foo\'\nif /foo/\n puts "TRUE!"\nend\n
Run Code Online (Sandbox Code Playgroud)\n\n产生:
\n\n$ ruby regex-in-conditional1.rb\nregex-in-conditional1.rb:1: warning: regex literal in condition\n
Run Code Online (Sandbox Code Playgroud)\n\n这是 Ruby 条件的正常规则的一个(记录很少)例外,其中任何 \xe2\x80\x99s 不false
或nil
评估为真的东西。
这仅适用于正则表达式文字,以下行为与您对条件的预期相同:
\n\nregex = /foo/\nif regex\n puts "TRUE!"\nend\n
Run Code Online (Sandbox Code Playgroud)\n\n输出:
\n\n$_ = \'foo\'\nif /foo/\n puts "TRUE!"\nend\n
Run Code Online (Sandbox Code Playgroud)\n\n这是在解析器中处理的。在 MRI 代码中搜索警告文本会产生一个匹配项parse.y
:
case NODE_DREGX:\ncase NODE_DREGX_ONCE:\n warning_unless_e_option(parser, node, "regex literal in condition");\n return NEW_MATCH2(node, NEW_GVAR(rb_intern("$_")));\n
Run Code Online (Sandbox Code Playgroud)\n\n我不认识 Bison,所以我可以准确解释这里发生的事情,但你可以推断出一些线索。如果已设置该选项,该函数只会warning_unless_e_option
抑制警告,因为在正常代码中不鼓励使用此功能,但在命令行表达式中可能很有用(这解释了为什么您在代码中看不到警告) -e
。下一行似乎正在构建一个解析子树,它是正则表达式和$_
全局变量之间的正则表达式匹配,其中包含 \xe2\x80\x9c [t]he 最后一个输入行的字符串 by gets 或 readline \xe2\x80\ x9d。然后这些节点将被编译到通常的正则表达式方法调用中。
这显示了正在发生的事情,I\xe2\x80\x99ll 只是引用文档中的内容来结束Kernel#gets
中的一段话来结束,这可能解释了为什么这是一个如此晦涩的功能
\n\n使用 $_ 作为隐式参数的编程风格逐渐在 Ruby 社区中失去青睐。
\n