In case it isn't obvious, I am not guessing about why what
you did worked and what the gotchas are. Consider the
following code:
my @list = 1..8;
my @ref_list;
foreach my $i (@list) {
push( @ref_list, sub { print " \$i == $i\n" } );
}
foreach my $i (@list) {
$i = "gone";
}
print "for SCALAR LIST\n";
while ( $code_ref = pop @ref_list ) {
&$code_ref;
}
Do you see what happened there?
Nope. It was not an accident that your code worked.
Perl worked exactly as documented.
But if you code that way without understanding why
it works, then you will get bitten eventually.
I am saying that because I have been there, done that, and
bear the scars. Else I wouldn't care enough to offer
advice.
Incidentally you would be well advised to stop using my
as if it was a global declaration. What you call "in the
normal way" I call "ill-advised". See RE (3): BrainPain-Help for
my attempt to explain why. See how I used it above,
moving the "my" as close to the initialization of the
variable as possible? I do things that way on purpose.
A final note. Here is what I meant by making absolutely
sure that you create a new variable each time:
for (my $i = 1; $i <= 8; ++$i) {
my $really_private = $i;
push( @ref_list, sub { print "\t$really_private\n" } );
}
$_->() foreach @ref_list;
See? I am explicitly using a variable scoped to be private
per instance of the loop. If this appears cumbersome, it
makes more sense in a constructor. Take this simple
example:
sub ret_simple_formatter {
my $fmt = shift;
return sub {sprintf($fmt, shift);};
}
Call that in a loop and it just works perfectly. :-)
BTW I have used almost exactly that function while
developing code to set
up a hash of field handlers. As the code matured, of
course, most of the fields got better formatters than that.
But it worked nicely for a first pass... |