根据Bool
类的the documentation,Regex
方法...
与调用者的$ _变量匹配,对于匹配项返回True,否则将返回False。
但是,在此示例中
$_ = "3";
my regex decimal { \d };
say &decimal.Bool;
返回False
。另外,looking at the source听起来很有意义,因为它将匹配$!topic
实例变量。但是,尚不清楚此变量将有效地对应于$ _,并且上面的示例似乎是这样说的。对实际发生的事情有任何想法吗?
答案 0 :(得分:9)
简短的回答:文档对于6.c来说是准确的,但是确切的语义并不像“调用者”那样简单(实际上,它存在真正奇怪的bug的风险)。改进的行为是:
/.../
和rx:i/.../
之类的形式构造的匿名正则表达式将在代码中到达$_
和$/
的位置(填充{{1} }问题中提到的变量。$!topic
和Bool
将导致与捕获的sink
匹配,并将结果$_
对象存储到该Match
中,前提是该对象可写。由于此行为仅适用于匿名正则表达式,因此您需要编写:
$/
答案很长。 $_ = "3";
my regex decimal { \d };
say /<&decimal>/.Bool;
-原因匹配行为的目标首先是要使这种事情起作用:
Bool
在这里,for $file-handle.lines {
.say if /^ \d+ ':'/;
}
循环填充主题变量for
,而$_
提供了布尔上下文。最初的设计是if
将查看呼叫者的.Bool
。但是,这存在许多问题。考虑:
$_
在这种情况下,for $file-handle.lines {
.say if not /^ \d+ ':'/;
}
是not
上.Bool
的调用者。但是,Regex
也将拥有自己的not
,与任何子例程一样,其将初始化为$_
。因此,从理论上讲,匹配将不起作用。除此之外,因为实际实现的方法是遍历调用者,直到找到包含定义值的Any
!这听起来很糟糕。考虑如下情况:
$_
如果sub foo() {
$_ = some-call-that-might-return-an-undefiend-value();
if /(\d+)/ {
# do stuff
}
}
$_ = 'abc123';
foo();
内部的调用要返回一个未定值-也许是出乎意料的-匹配将继续沿调用者链移动,而在foo
的调用者中找到$_
的值foo
。实际上,我们可以在调用堆栈中走很多个台阶! (此外:是的,这也意味着在$/
上也要更新结果的复杂性!)
以前的行为还要求$_
具有动态范围-即可供呼叫者查找。但是,具有动态作用域的变量会阻止大量分析(包括编译器和程序员的分析),因而无法进行优化。在许多使用$_
的习惯用法中,这似乎是不可取的(没有人希望看到Perl 6性能指南建议“不要在热代码中使用with foo() { .bar }
,而应使用with foo() -> $x { $x.bar }
”)。因此,6.d
将$_
更改为常规词汇变量。
6.d $_
的范围变更几乎没有实际影响,但是确实导致了.Bool
上.sink
和Regex
的语义被检查,因为它们是依靠$_
动态的一种常用东西。这反过来揭示了我刚刚描述的“第一个定义的$_
”行为-在这一点上,动态范围的使用开始看起来更多是危险而不是好处!
新的语义意味着编写匿名正则表达式的程序员可以依靠它与$_
匹配并更新$/
,这在他们编写正则表达式的范围内是可见的-解释起来似乎比较简单,并且-如果它们以未定义的$_
结尾,那就不奇怪了!