snoofkin
snoofkin

Reputation: 8895

Perl Switch Statement

Is there any way to run a block of code if none of the case blocks were matched? For instance:

switch($a) {

  case // {}
  case // {}
  ...
  # DO SOMETHING IF NONE OF THE ABOVE CASES WERE MATCHED
}

else is not what I'm looking for, since it applies only to the last case block.

Upvotes: 24

Views: 68516

Answers (10)

null
null

Reputation: 928

No need for feature.

Is perlcritic safe. I have used this with 20+ options after converting from an else-if chain.

my $key = 'fruity';  # User chosen value
my %code_ref = (
    apple => sub { print("Apple\n"); },
    pear => sub { my_other_code(); },
    orange => sub { my_still_other_code();  },
);
if ( exists $code_ref{$key} ) {
    $code_ref{$key}->();
}
else { # Default case
    print STDERR "$0: unknown option '$key'\n";
}

Upvotes: 2

P.Pscholka
P.Pscholka

Reputation: 1

I wrote and use these three Perl subroutine switches and find them very useful.

sub switchOne($){          # standard switch
my($prefix,$testVal,@caseVals)=@_;
$s=0;
    while($s<scalar(@caseVals)){
        if($testVal eq $caseVals->[$s]){
            return $prefix."_".$testVal;
        }
        $s++;
    }
return $prefix."Not";
}

sub switchTwo($){         # test for 2 conditions switch = mapping x & Y
my($prefix,$testVal1,$testVal2,@caseVals1,@caseVals2)=@_;
$s=0;
    while($s<scalar(@caseVals)){
        if($testVal1 eq $caseVals1->[$s] && $testVal2 eq $caseVals2->[$s]){
            return $prefix."_".$testVal1;
        }
        $s++;
    }
return $prefix."Not";
}

sub switchRange($){         # test for range switch
my($prefix,$testVal1,@caseVals1,@caseVals2)=@_;
$s=0;
    while($s<scalar(@caseVals)){
        if($testVal > $caseVals->[$s]&&$testVal < $caseVals2->[$s]){
            return $prefix."_".($s+1);
        }
        $s++;
    }
return $prefix."Not";
}


#############  here is the calling code 
$prefix="case";
@cases=(1,12,3,45,5,61,7,8,9,10);       # cases to test against / quote strings
$case=&switchOne($prefix,$testvariable,\@cases);  

# prefix must be different for each switch call for different labels
#duplicate labels can cause problems

while($case ne ""){
    # initialization common code block

    goto $case;

case_1:                #   cases in array
    #code
    last;

case_12:
     # code
     last;


case_61:
    last;
case_7:
    last;    
case_8:
    last;
case_9:
    last;
case_10:
    last;

caseNot:
     # no match comes here

     #code
     last;
}

#  here is a dbl variable matching call example
# prefix can be in the call quoted
# both cases must be true to get a match

$case=&switchTwo("intrsctn",$test1,$test2,\@cases1,\@cases2);
while($case ne ""){
    # initial code as desired
    goto $case;

intrsctn_1:  
     # code
     last;

# as many labels as cases

intrsctnNot:
    last;
}

# here is a switch example to test for a variable in a range (between)

$case=&switchRange("thscase",$testvariable,\@cases1,\@cases2);
while($case ne ""){

        goto $case;

thscase_1:       # this returns the array index +1 on the prefix
     # code
     last;

# as many labels as cases

thscaseNot:
    # N must be uppercase
    last;
}

Upvotes: -1

Gordon Freeman
Gordon Freeman

Reputation: 911

This statement return Case 2:

my $test = 'abcd';

print test($test);

sub test {
    for ($_[0]) {
        /ad/ && return 'Case 1';
        /bc/ && return 'Case 2';
        /c/ && return 'Case 3';
    }
}

This one return Case 3:

my $test = 'abcd';
my $result;

for ($test) {
    /ad/ && do { $result = 'case 1' };
    /bb/ && do { $result = 'case 2' };
    /cd/ && do { $result = 'case 3' };
}

print $result;

This one Case 2:

my $test = 'abcd';
my $result;

for ($test) {
    /ad/ && do { $result = 'case 1'; last };
    /bc/ && do { $result = 'case 2'; last };
    /cd/ && do { $result = 'case 3'; last };
}

print $result;

Default:

my $test = 'abcd';
my $result;

for ($test) {
    /aa/ && do { $result = 'case 1'; last };
    /bb/ && do { $result = 'case 2'; last };
    /cc/ && do { $result = 'case 3'; last };

    $result = 'Default';
}

print $result;

Upvotes: 6

Swadhikar
Swadhikar

Reputation: 2210

I usually use the below block construct which is more simple and no need to import anything.

SWITCH: {
    if($key =~ /^abc/) { $key = "key starts with abc"; last SWITCH; } # 'last' breaks the 'SWITCH' block
    if($key =~ /^def/) { $key = "key starts with def"; last SWITCH; }
    if($key =~ /^ghi/) { $key = "key starts with ghi"; last SWITCH; }   
    $key = "Default value";
}

print $key;

Upvotes: 8

Hans Ginzel
Hans Ginzel

Reputation: 8850

If you only need to decide an assignment use the ternary operator ?:

die "Expecting name of the system (reise/synpac/vias) as parameter.\n"
    unless $_ = shift;
@opt{qw/Name Code Id UID/} =
    /^\s*rei(?:se)?\s*$/i   ? qw/ CEP    REI    80 ipcp_rei / :
    /^\s*syn(?:pac)?\s*$/i  ? qw/ SYNPAC SYNPAC 67 ipcp_sym / :
    /^\s*vias?\s*$/i        ? qw/ VIAS   VIAS   68 ipcp_via / :
    do { die "Unknown system ‘$_’.\n"; };   # or default values

Upvotes: 1

cyber-guard
cyber-guard

Reputation: 1846

Please note that use Switch in any form is deprecated as it is being replaced (and removed in the next perl release) by perl's own form of switch statement, which is, as already answered:

use feature qw(switch);

given ($x)
{
when ('case1') { print 1; }
default {print 0; }
}

Using default case achieves the outcome you want. Also don't forget to use last if you want the switch to stop being evaluated after one condition is evaluated true.

Upvotes: 12

chambwez
chambwez

Reputation: 456

There's always the switching in Perl 5.10, if you're running it of course.

use feature qw(switch);

given($a){
  when(1) { print 'Number one'; }
  when(2) { print 'Number two'; }
  default { print 'Everything else' }
}

Upvotes: 42

Nylon Smile
Nylon Smile

Reputation: 9446

"else is not what I'm looking for, since it applies only to the last case block."

As long as you are not using fall-through:

use Switch 'fallthrough';

You are safe.

If you reach the last case statement it means none of the case statements above it matched the criteria. In other words (if there is no fall-through) the else statement is only executed if all case statements fail to satisfy their conditions.

Upvotes: 3

Tim
Tim

Reputation: 14164

else is indeed what you are looking for.

switch ( $n ) {
    case 1 { print "one\n" }
    case 2 { print "two\n" }
    else   { print "other\n" }
}

The above would output "other" for $n=3 and "one" for $n=1.

Upvotes: 5

Simon Whitaker
Simon Whitaker

Reputation: 20576

Assuming you're using use Switch, you can use an else clause

Upvotes: 1

Related Questions