Say I have a number, $x = 0;
and I want to increment it with a subroutine, but the subroutine won't be returning its value:
sub increment {
my ($var) = @_;
my @list = (
'a',
'b',
'c',
...
'x',
'y',
'z'
);
return $list[$var++];
}
while ($x < 10) {
print increment($x);
}
As-is, this will print aaaaaaaaaa
forever instead of abcdefghij
. If I replace increment($x)
with increment(\$x)
, it converts the scalar address to a decimal number and increments that instead. In the above scenario, it ends up throwing an error because 25423331 or whatever isn't a valid array element.
If $x were an element in a hash or an array, I could pass the parent as a reference to have the original modified:
$x = {'val' => 0};
while ($x->{'val'} < 10) {
print increment($x);
}
sub increment {
...
return $list[$var->{$val}++];
}
How can I modify the original value of a scalar reference?
You can pass a reference to the variable to modify.
sub increment {
my ($ref) = @_;
++$$ref;
}
my $i = 0;
say $i; # prints 0
increment(\$i);
say $i; # prints 1
You could also take advantage of the fact that Perl passes by reference.
sub increment {
++$_[0];
}
my $i = 0;
say $i; # prints 0
increment($i);
say $i; # prints 1
But hiding the increment as such is a really bad idea. Either iterate over a list,
for my $x ('a'..'z') {
...
}
Or write an iterator.
sub make_iter {
my @list = @_;
return sub {
return @list ? shift(@list) : ();
};
}
my $iter = make_iter('a'..'z');
while (my ($x) = $iter->()) {
...
}
You need to dereference $var
inside the subroutine, like this:
my $x = 0;
say $x; # prints 0
foo(\$x);
say $x; # prints 1
sub foo {
my $y = shift;
$$y++;
}
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