Краткий ответ: документация была довольно точной для 6.c, однако точная семантика была вовсе не такой простой, как у «вызывающего» (и на самом деле содержала риск действительно странных ошибок). Уточненное поведение:
- Анонимные регулярные выражения, построенные в таких формах, как
/.../
и rx:i/.../
, будут захватывать $_
и $/
в той точке, в которой они достигнуты в коде (заполняя переменную $!topic
, упомянутую в вопросе).
Bool
и sink
вызовут совпадение с захваченным $_
и сохранят полученный объект Match
в этом $/
, при условии, что он доступен для записи.
Поскольку это относится только к анонимным регулярным выражениям, вам нужно написать:
$_ = "3";
my regex decimal { \d };
say /<&decimal>/.Bool;
Вот длинный ответ. Целью поведения Bool
-causes-match в первую очередь было то, чтобы сработали такие вещи:
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
, поскольку они были единственной часто используемой вещью. это полагалось на $_
, являющийся динамическим. Это, в свою очередь, пролило свет на «первое определенное $_
» поведение, которое я только что описал, - в этот момент использование динамического определения области видимости стало больше представлять опасность, чем выгоду!
Новая семантика означает, что программист, пишущий анонимное регулярное выражение, может полагаться на него, сопоставляя $_
и обновляя $/
, которые видны в области, в которой они написали регулярное выражение - что кажется более простым для объяснения, и - в в случае, если они получат $_
, который не определен - гораздо менее удивительно!