I found a possible bug in perl's closures and $1
regexp variables. Simply, they don't mix together.
Let's take this code.
use warnings;
while ("1234567890"=~/(.)/sg) {
push @subs, sub{print $1;};
}
for (@subs) {$_->()}
You would imagine that perl will now print all the numbers - instead, I got 10 warnings from undefined $1
.
Is it really a bug, or did I just missed something in perl documentation? Is there some reason, why should $1
be undefined and NOT being part of the closure?
Perl has two separate but largely compatible variable systems. Global variables, which are in the symbol table, and lexical variables which are in scope bound lexical pads.
Global variables can be the target of a symbolic dereference and are subject to dynamic scope with local
. Lexical variables (defined with my
) can be closed over.
The regex match variables (and all of Perl's other special variables) are global variables in the symbol table, thus there is no way to close over them.
To fix this, just copy the value into a lexical:
use warnings;
while ("1234567890"=~/(.)/sg) {
my $x = $1; # creates a new lexical that the sub closes over
push @subs, sub{print $x;};
}
for (@subs) {$_->()}
I think the answer is similar to the answer to perl closures and $_. $1
is a global variable, too.
What you need to do is:
my $x = $1;
push @subs, sub{print $x;};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With