Reputation: 5153
When I type in the following code and run it, it types <FONT COLOR='foo'></FONT>. However, when I add my
to the loop variable (for my $name (@colors)
), it types the expected <FONT COLOR='red'></FONT>. Can anyone explain why?
@colors = qw(red blue green yellow orange purple violet);
$name = 'foo';
for $name (@colors) {
no strict 'refs';
*$name = sub { "<FONT COLOR='$name'></FONT>" };
}
print red();
Upvotes: 2
Views: 92
Reputation: 385897
Closures capture variables, not values.
Think of for my $x
as creating a new variable every time through the loop. The inner sub captures this variable instead of the similarly named package variable whose value never changes from foo
.
When you remove the my
, only one variable is created (a package variable), so each sub created in the loop refes to the same variable (whose value goes from foo
to red
to blue
to ... to violet
to foo
).
Upvotes: 2
Reputation: 1420
The variable used in a for loop has some magic attached to it. For each iteration of the loop, it is set to the appropriate value. After the end of the loop, $name is set to it's old value. Basically, every sub you create sees the same variable which changes it's value. I've modified your example to demonstrate this:
@colors = qw(red blue green yellow orange purple violet);
$name = 'foo';
for $name (@colors) {
no strict 'refs';
*$name = sub { "<FONT COLOR='$name'></FONT>" };
print $name . &{$name} . "\n";
}
print red() . "\n";
You can create a local variable by defining it with the function my
like this:
for my $name (@colors) {
As a rule of thumb, you should always use strict;
in your programs, which enforces initialization of variables.
Upvotes: 1
Reputation: 57640
In your loop you create several subs. These subs can see all the variables of the context that they are created in.
If we use local / global variables, the sub will always see the latest value (The interpolation of the variable into the string does'nt happen at compile-time or "definition-time", but when the sub is executed.) In our case, the current value outside the loop is foo
.
If we use lexical variables with my
, the variable that we used inside the loop is invisible outside of the loop and invisible in all other iterations of the loop. However, it is still visible to the sub itself. This is called a closure. Closures only work with lexical variables and are a powerful method to achieve information hiding or to construct specifically tailored subs like in the example code.
Upvotes: 3