Damit eine Funktion einen Wert zurückliefern kann, benötigen
Sie das Schlüsselwort
return. Hier ein Beispiel wie Sie einen Wert aus einer Funktion zurückgeben können ...
#!/usr/bin/perl -w
sub fakul
{
my $x=$y=$_[0];
while(--$x) #Solang $x-1 bis 0
{
$y*=$x;
}
return $y; #Rückgabewert der Funktion fakul
}
print "Fakultätberechnung! Von welcher Zahl : ";
chomp ($var=<STDIN>);
$ergebnis=fakul($var);
#Funktion fakul gibt das Ergebnis mittels return zurück
print $ergebnis , "\n";
Die berühmte Berechnung der Fakultät, die in fast jeder Programmiersprache demonstriert wird. Hier sehen
Sie also wie mittels return $y der Wert an den Funktionsaufruf ...
$ergebnis=fakul($var);
... an die Variable $ergebnis übergeben wird. Jetzt werden Sie sich sicherlich
fragen, ob es in Perl auch möglich ist, wie in anderen Programmiersprachen,
die Fakultät, Rekursiv zu berechnen. Hier das Beispiel
Fakultät rekursiv ...
#!/usr/bin/perl -w
sub fakul
{
my $x=$_[0];
if($x) #Abbruchbedienung der Rekursion
{
return $x * fakul($x-1); #Rekursiver Aufruf
}
return 1;
}
print "Fakultätberechnung! Von welcher Zahl : ";
chomp ($var=<STDIN>);
$ergebnis=fakul($var);
#Funktion fakul gibt das Ergebnis mittels return zurück
print $ergebnis , "\n";
Ich möchte jetzt nicht so genau darauf eingehen. Doch für Anfänger sei kurz zur Rekursion gesagt:
Eine Rekursion ist eine Funktion die sich immer wieder selbst aufruft bis eine bestimmte Bedingung erfüllt ist. Diese Bedingung stellt gleichzeitig die Abbruchbedienung der Rekursion dar.
Mit dem Schlüsselwort return wird auch eine Funktion beendet. Beispiel ...
#!/usr/bin/perl -w
sub func
{
print "Ich werde ausgegeben\n";
return 1;
print "Ich leider nicht mehr\n";
}
func();
In diesem Beispiel wird nur die erste print-Anweisung ausgeführt. Die zweite nicht mehr, da die Funktion an den Aufrufer den Wert 1 zurückgibt und sich somit beendet. Nicht wegen des Wertes 1 sondern wegen
dem Schlüsselwort return. Sie können diese Beispiel ja auch mal ohne den Wert 1 schreiben.
In Perl ist es möglich, während der Laufzeit Programmcode dynamisch zu erzeugen und Auszuführen. eval() ist eine sehr mächtige Funktion. Ich werde
daher nur auf die Grundlegenden Funktionen von
eval() eingehen.
eval() können Sie auf zwei Verschiedenen Arten verwenden. Zum einen als Codeangabe in Strings ...
#!/usr/bin/perl -w
print "Bitte geben Sie einen Code ein : ";
chomp($code=<>);
eval $code; #Code wird ausgeführt
Sie können ja Beispielsweise folgendes eingeben ...
Bitte geben Sie einen Code ein : print $value=20*10 , "\n";
Die Ausgabe ist anschließend 200. Vorraussetzung ist natürlich, dass
Sie auch ausführbaren Code eingegeben haben.
Von der Stringmethode, Code zu evaluieren, wird aber aus Sicherheitsgründen abgeraten. Da man nicht davon ausgehen kann,
dass alle Benutzer einfache Anwender sind, kann ein Übelgesinnter schnell dazu Übergehen, gefährlichen Code einzugeben.
Die zweite Möglichkeit ist es, denn Code in geschweiften Klammern zu Schreiben ...
#!/usr/bin/perl -w
while(1){
eval { $wert1=<>; $wert2=<>; $erg=$wert1/$wert2 };
print "Ergebnis : $erg \n" unless $@;
}
Der Vorteil an dieser Schreibweise ist, dass der Code, zur Kompilierzeit nur einmal geparst wird. Geben
Sie in diesem Beispiel als Wert ein ungültiges Zeichen ein, wird anstatt
einem Programmabbruch, ein Fehlercode ausgegeben. Dieser Fehlercode befindet sich in der reservierten Variablen $@. Tritt kein Fehler auf, ist diese Variable leer.
Eine Sinnvolle Anwendung der Funktion eval() wäre die Auswertung einer Ausnahmebehandlung
mit try() und catch() wie dies in C++ oder Java verwendet wird ...
try{ /*Code der Ausnahme auslösen könnte*/ }
catch { /*Code der die Ausnahme behandelt*/ }
Und hier das ganze in der Praxis ...
#!/usr/bin/perl -w
$wert1=<>;
$wert2=<>;
chomp $wert1;
chomp $wert2;
eval { $ergebnis=$wert1/$wert2; }
or do{ print "FEHLER_HANDLER : $@\n" if $@;
$ergebnis=0;
};
print "$ergebnis \n";
Mit diesem Programm können Sie zum Beispiel verhindern, dass das Programm bei einer Division durch 0, nicht
abrupt abgebrochen wird. In eval{...} evaluieren wir den Code. Falls eine reguläre Division erfolgt, wird dies als Ergebnis ausgegeben. Falls
Sie aber zum Beispiel 5/0 rechnen wollen, geht es in den or do Anweisungsblock. In diesem wird die reservierte eval-Fehler-Variable ($@) überprüft, ob sich darin etwas befindet.
Falls ja, wird der Fehlerhandler ausgeführt und die Variable $ergebnis auf 0 gesetzt.
Wie gesagt das Thema eval() ist sehr Umfangreich und es wurde nur kurz behandelt.
Wenn Sie eine kontexintesive Funktion schreiben wollen, ist auch dies in Perl kein Problem. Mit der Funktion wantarray()
können Sie überprüfen, ob Ihre Funktion im Listenkontex aufgerufen wurde (true)
oder im skalaren Kontex (false). Dabei gehen Sie wie folgt vor ...
sub func{
if(wantarray){
#Rückgabewert ist @array
}
else{
#Rückgabewert $skalar
}
}
Und so sieht eine Kontexintesive Funktion in der Praxis aus ...
#!/usr/bin/perl -w
sub kontex{
if(wantarray){
my @add = @_;
my $tmp;
foreach $add(@add){
$add=$tmp+=$add;
}
return @add;
}
else{
my($tmp, $add);
foreach $add(@_){
$tmp+=$add;
}
return $tmp;
}
}
@liste = (1..10);
$tot = kontex(@liste);
print $tot , "\n";
@res = kontex(@liste);
print "@res\n"
Memoizing ist eine Technik die viele aufwendige Funktionen in Perl beschleunigen kann.
Die Prinzip funktioniert mit einer Cache in der bereits gerechnete Ergebnisse zwischengespeichert werden. Bei einer erneuten Berechnung mit der Funktion wird also erst mal in die Cache
gesehen, ob dieser bereits berechnete Werte dazu beinhaltet. Falls ja, wird die Cache verwendet und es kann auf eine erneute aufwendige Berechnungen verzichtet werden. Befindet sich kein bereits berechneter Wert in der Cache, muss eben eine aufwendige Berechnung durchgeführt werden.
Am besten können Sie das ganze Anhand der Berechnung der Fibonaccizahlen
sehen ...
#!/usr/bin/perl -w
{
local %cache;
sub fibonacci_cache{
return 1 if $_[0] == 0 || $_[0] == 1;
return $cache{$_[0]} if exists $cache{$_[0]};
return $cache{$_[0]} = fibonacci_cache($_[0]-1) + fibonacci_cache($_[0]-2);
}
}
sub fibonacci_nocache{
return 1 if $_[0] == 0 || $_[0] == 1;
return fibonacci_nocache($_[0]-1) + fibonacci_nocache($_[0]-2);
}
print "Fibonacci mit Cache........\n";
$fib1 = fibonacci_cache(30);
print $fib1 , "\n";
print "Fibonacci ohne Cache.........\n";
$fib2 = fibonacci_nocache(30);
print $fib2 , "\n";
Die Berechnung mit Cache (fibonacci_cache) ist von der Zeit her nicht Erwähnenswert. Ohne Cache dagegen warten
Sie hier schon ein paar Sekunden.
Die Unterbringung des Caches mussten Sie in einem Block mit einer dynamischen lokalen Variablen verwenden.
Obwohl hier ein Hash verwendet wurde, muss dies nicht unbedingt so gemacht werden. Im Gegenteil, mit Arrays könnten
Sie die Perfomance noch mehr Beschleunigen, da Array weniger Speicher benötigen.
Memoizing würde sich auch sehr gut für eine aufwendige Sortierung eignen.
|