Question

So, I never knew this and I want to get some clarifcation on it. I know if you do

foreach (@list){

if you change $_ in that loop it will affect the actual data. But, I did not know that if you did

foreach my $var1 (@list){

If you changed $var1 in the loop it would change the actual data. :-/ So, is there a way to loop over @list but keep the variable a read-only copy, or a copy that if changed will not change the value in @list?

Was it helpful?

Solution

$var is aliased to each item in turn.

See http://perldoc.perl.org/perlsyn.html#Foreach-Loops

If any element of LIST is an lvalue, you can modify it by modifying VAR inside the loop. Conversely, if any element of LIST is NOT an lvalue, any attempt to modify that element will fail. In other words, the foreach loop index variable is an implicit alias for each item in the list that you're looping over.

OTHER TIPS

Easiest way is just to copy it:

foreach my $var1 (@list) {
    my $var1_scratch = $var1;

or

foreach my $var1 ( map $_, @list ) {

But if $var1 is a reference, $var1_scratch will be a reference to the same thing. To be really safe, you'd have to use something like Storable::dclone to do a deep copy:

foreach my $var1 ( @{ Storable::dclone( \@list ) } ) {
}

(untested). Then you should be able to safely change $var1. But it could be expensive if @list is a big datastructure.

It is an alias, not a reference. If you want to create your own aliases (outside of for) you can use Data::Alias.

The only difference between these loops:

foreach (@array) { ... }
foreach my $var (@array) { ... }

is the loop variable. The aliasing is a function of foreach, not the implicit variable $_. Note that this is an alias (another name for the same thing) and not a reference (a pointer to a thing).

In the simple (and common) case, you can break the aliasing by making a copy:

foreach my $var (@array) {
    my $copy = $var;
    # do something that changes $copy
}

This works for ordinary scalar values. For references (or objects) you would need to make a deep copy using Storable or Clone, which could be expensive. Tied variables are problematic as well, perlsyn recommends avoiding the situation entirely.

I don't know how to force the variable to be by-value instead of by-reference in the foreach statement itself. You can copy the value of $_ though.

#!/usr/perl/bin
use warnings;
use strict;

use Data::Dumper;

my @data = (1, 2, 3, 4);

print "Before:\n", Dumper(\@data), "\n\n\n";

foreach (@data) {
    my $v = $_;
    $v++;
}

print "After:\n", Dumper(\@data), "\n\n\n";

__END__

Make a copy of @list in the for statement:

foreach my $var1 (() = @list) {
  # modify $var without modifying @list here
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top