Reputation: 23
Can any one help to find easy way to call subroutines in a loop? Now, I called them as below manually. How do I do that programmatically?
&case1Validate($fTxt);
&case2Validate($fTxt);
&case3Validate($fTxt);
&case4Validate($fTxt);
&case5Validate($fTxt);
&case6Validate($fTxt);
&case7Validate($fTxt);
&case8Validate($fTxt);
&case9Validate($fTxt);
&case10Validate($fTxt);
Upvotes: 2
Views: 466
Reputation: 46187
strict 'refs'
complains about indirect references ("using a variable as a variable name") for a reason. Several reasons, in fact, most of them having to do with indirect references reducing your ability to debug and maintain your code.
The better way to do this is to create an array of code references and iterate over that, calling each in turn:
#!/usr/bin/env perl
use strict;
use warnings;
use 5.010;
sub case1Validate { return 'Case 1: ' . $_[0] }
sub case2Validate { return 'Case 2: ' . $_[0] }
sub case3Validate { return 'Case 3: ' . $_[0] }
my @validators = (\&case1Validate, \&case2Validate, \&case3Validate);
for my $sub (@validators) {
say $sub->('foo');
}
Another technique, which is very useful in cases where you might not want to call every sub every time, and always in the same order, is to use a hash as a dispatch table:
#!/usr/bin/env perl
use strict;
use warnings;
use 5.010;
sub case1Validate { return 'Case 1: ' . $_[0] }
sub case2Validate { return 'Case 2: ' . $_[0] }
my %validators = (
case1 => \&case1Validate,
case2 => \&case2Validate,
# If the sub is small and you're not using it separately, you can even define
# it in-line!
case5 => sub { return 'Case 5: ' . $_[0] }
);
for my $i (1 .. 5) {
# Because of "exists", will only attempt to print for cases 1, 2, and 5,
# since cases 3 and 4 don't exist
say $validators{"case$i"}->('foo') if exists $validators{"case$i"};
}
Upvotes: 9
Reputation: 54323
You need to build the function name into a variable first, and then turn off use strict 'refs'
. After that, you can call it using the ampersand &
.
use strict;
use warnings;
sub case1Validate { return $_[0] }
sub case2Validate { return $_[0] }
sub case3Validate { return $_[0] }
for my $i ( 1 .. 3 ) {
no strict 'refs';
my $sub_name = 'case' . $i . 'Validate';
CORE::say &{$sub_name}( $i );
}
This program will output
1
2
3
Make sure to disable strict 'refs'
in the smallest possible scope. If you do not turn it off, you will get the error
Can't use string ("case1Validate") as a subroutine ref while "strict refs" in use
Note that this is just one of several solutions, and in most cases it should not be the preferred one. It's better to create a dispatch table (or a list of code refs, like Dave explains in his excellent answer) because that way you have better control over what happens inside your program.
Since you're iterating a list of functions now you can use exists
to check if they exist before calling them.
&{ $sub_name }( $i) if exists &$sub_name; # both &{} and & are fine
The same should be done with a dispatch table where you create the keys on the fly.
Upvotes: 0