在正则表达式上调用Bool无法正常工作

时间:2019-06-29 07:46:19

标签: regex oop perl6

根据Bool类的the documentationRegex方法...

  

与调用者的$ _变量匹配,对于匹配项返回True,否则将返回False。

但是,在此示例中

$_ = "3";
my regex decimal { \d };
say &decimal.Bool;

返回False。另外,looking at the source听起来很有意义,因为它将匹配$!topic实例变量。但是,尚不清楚此变量将有效地对应于$ _,并且上面的示例似乎是这样说的。对实际发生的事情有任何想法吗?

1 个答案:

答案 0 :(得分:9)

简短的回答:文档对于6.c来说是准确的,但是确切的语义并不像“调用者”那样简单(实际上,它存在真正奇怪的bug的风险)。改进的行为是:

  • /.../rx:i/.../之类的形式构造的匿名正则表达式将在代码中到达$_$/的位置(填充{{1} }问题中提到的变量。
  • $!topicBool将导致与捕获的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.sinkRegex的语义被检查,因为它们是依靠$_动态的一种常用东西。这反过来揭示了我刚刚描述的“第一个定义的$_”行为-在这一点上,动态范围的使用开始看起来更多是危险而不是好处!

新的语义意味着编写匿名正则表达式的程序员可以依靠它与$_匹配并更新$/,这在他们编写正则表达式的范围内是可见的-解释起来似乎比较简单,并且-如果它们以未定义的$_结尾,那就不奇怪了!