Wo finde ich in Perl eine switch()-Funktion?
Inhalt:
Du vermisst die switch()-Funktion, die du aus C oder Basic kennst?
Du kommst von einer anderen Programmiersprache wie Basic oder C und vermisst
die switch-Funktion? Leider gibt es die in Perl nicht. Da jedoch Perl
eine so mächtige Sprache ist, kann man es sich selbst auf verschiedene
Arten bauen. Einige Hinweise dazu findest du auch in der Perl-Dokumentation mit
perldoc -q switch
Der neue Weg
Seit Perl 5.10.0 gibt es ein neues Konstrukt, das mehr ist als das switch aus anderen Sprachen.
In Perl 5.10 heißt das Konstrukt "given/when". Um die Kompatibilität zu früheren Perl-Versionen
aufrecht zu halten, muss man dieses neue Feature extra einschalten. Entweder über
use 5.010;
oder mit
use feature 'switch';
Danach kann man "given/when" verwenden:
#!/usr/bin/perl
#use 5.010;
use feature 'switch';
my $c = 't';
given( $c ) {
when( 't' ){
print "t";
};
when( 1 ){
print "1";
};
}
Das sieht jetzt nicht so aus, als könnte es mehr als andere Sprachen, aber der Clou liegt in den Vergleichen
bei "when". Dort wird der sogenannte
SmartMatch?-Operator verwendet. Damit kann man z.B. überprüfen, ob ein
Element in einem Array vorhanden ist - und noch viel mehr.
#!/usr/bin/perl
#use 5.010;
use feature 'switch';
my $c = 't';
my @array = qw(a b c t);
given( $c ) {
when( @array ){
print "yes";
};
}
Der klassische Weg
SWITCH:
{
if ($key == 1) { &Sub1($key,10); last SWITCH; }
if ($key == 2) { &Sub2($key,10); last SWITCH; }
if ($key == 3) { &Sub3($key,10); last SWITCH; }
}
Mit Hash von Referenzen auf Subs
# Vorbereiten der Verweise auf die Subs:
my %switch = (
1 => \&Sub1,
2 => \&Sub2,
3 => \&Sub3,
);
# Überprüfen, ob Verweis auf Funktion definiert
if (exists $switch{$key} ) {
# Wenn ja, dann die Funktion ausführen und dabei eventuell
# Parameter übergeben (hier: 1,2,3)
$switch{$key}->(1,2,3); # Pfeil-Schreibweise
} else {
# Wenn nein, dann einen Fehler ausgeben. Man könnte hier z.B. auch
# auf eine Standardfunktion (=Default) umleiten.
print "Fehler: Element nicht vorhanden\n";
}
# oder mit anderer Schreibweise:
if (exists $switch{$key}){
&{ $switch{$key} }(4,5,6); # explizite dereferenzierung
} else {
print "Fehler: Element nicht vorhanden\n";
}
Evaluierung zur LaufZeit?
%switch = (
1 => "Sub1('hallo')",
2 => "Sub2()",
3 => "Sub3('irgendwelche Parameter')",
);
if (exists $switch{$key} ) {
eval $switch{$key};
} else {
print "Fehler: Element nicht vorhanden\n";
}
Evaluierung zur CompileZeit?
Bei den folgenden Beispielen wird nicht eine der Funktionen on-the-fly
ausgeführt, sondern es wird jede Funktion ausgeführt, und es
wird mit den Rückgabewerten gearbeitet. Eine solche Art von Switch
genügt in den folgenden Fällen:
- Die Parameter für die Funktion sind schon bekannt, wenn der Hash gebaut wird.
- Die Funktionen machen selbst keinen Input/Output, sondern liefern nur etwas (z.B. das Ergebnis einer Berechnung) zurück. Denn es werden alle Funktionen ausgeführt, und der Switch geht nur auf die Rückgabewerte der Funktionen.
- Die Funktionen laufen recht kurz. Falls sie eine längere Laufzeit benötigen sollten, ist wohl eher aus Effizienzgründen eine der Lösungen von oben angebracht.
Im ersten Beispiel werden alle zu berechnenden Werte beim Aufbau des Hashes
%switch berechnet:
my %switch = (
1 => &x1(1,3),
2 => &x2(2,3),
3 => &x3(3,3),
);
my $key = 1 ;
print $switch{$key}."\n";
Im zweiten Beispiel wird der Wert erst berechnet, wenn dieser tatsächlich benötigt
wird (VerzögerteAuswertung):
my %switch = ( # backslashes hinzugefuegt (StraT)
1 => \&x1,
2 => \&x2,
3 => \&x3
);
my $key = 3 ;
print &{$switch{$key}}(9,9)."\n";
# oder: print $switch{$key}->(9,9), "\n"; # (StraT)
sub x1 { $_[0] * $_[1]; }
sub x2 { $_[0] * $_[1]; }
sub x3 { $_[0] * $_[1]; }
Ausnutzung der KurzSchlussF?ähigkeit von Perl
my $name = "hase";
$name eq "hund" and do { print $name } or
$name eq "katz" and do { print $name . "!" } or
$name eq "hase" and do { print $name . "!!" };
Das Switch Modul
Das Switch Modul ist eine Implementierung des switch Statements auf
SourceFilter?
Basis. Seit Perl 5.8.0 ist es ein
StandardModul.
use Switch;
my $val = rand (100);
switch ($val) {
case 1 { print "number 1" }
case "a" { print "string a" }
case [1..10,42] { print "number in list" }
case (@array) { print "number in list" }
case /\w+/ { print "pattern" }
case qr/\w+/ { print "pattern" }
case (%hash) { print "entry in hash" }
case (\%hash) { print "entry in hash" }
case (\&sub){ print "arg to subroutine" }
else { print "previous case not true" }
}
Exkurs: Die C Implementierung
Die Sprache C enthält - anders als Perl - bereits ein Statement
switch.
#include <stdlib.h>
#include <stdio.h>
int main() {
int i=1;
switch(i) {
case 1: { Sub1("Hallo"); break; }
case 2: { Sub2(); break; }
case 3: { Sub3(); break; }
}
return 0;
}
char Sub1(char str) { return str; }
int Sub2() { printf("sub2\n"); }
int Sub3() { printf("sub3\n"); }
--
TinaMueller,
StefanHanke,
HaraldBongartz - 15 Aug 2003