
Was sind Referenzen?
Auf einen Zeiger zugreifen
Auf einen gesamten Array zugreifen
Einem Array Werte zuweisen
Alternative Möglichkeiten, um auf einzelne
Elemente eines Arrays zuzugreifen
Auf einen gesamten Hash zugreifen
Einem Hash Werte zuweisen
Alternative Möglichkeiten, um auf einzelne
Werte eines Hashs zuzugreifen
Auf Variablen zugreifen
Anonymous Arrays/-Hashs
Mehrdimensionale Arrays/-Hashs
Anzeigen, was der Zeiger zeigt - Die Funktion
ref.
Arrays mit Zeigern auf anonymous Arrays/-Hashs
Unter Referenzen versteht man Zeiger auf Variablen,
Arrays, assoziative Arrays(Hashs) oder Subroutinen.
Die Frage ist, wozu sollen diese Referenzen gut sein. Die
Antwort auf diese Frage kann pragmatisch ausfallen, weil Perl
in der objektorientierten Programmierung mit Referenzen arbeitet
(Objektorientierte
Programmierung). Will man also objektorientiert programmieren
oder Module verwenden, dann macht es Sinn, eine Vorstellung
zu haben, welche Bedeutung Referenzen haben.
Wer dies intensiv studieren will, der kann zum Kapitel das
Cgi.pm Modul hopsen. Dort
wird ausführlich beschrieben wie ein Modul mit Referenzen
arbeitet.
Im übrigen tauchen Referenzen immer wieder in diesem
Handbuch auf. Auch bei XML auslesen
mit Perl spielen sie eine entscheidende Rolle. Das heißt
nicht, dass es ohne ein Verständnis von Referenzen nicht
möglich ist, mit Perl XML Dokumente zu parsen oder mit
Modulen zu arbeiten, aber es erleichtert das Verständnis.
Mit Referenzen kann man auch mehrdimensionale Arrays in Perl
nachbauen, ja man kann sogar Konstrukte bauen, die noch weit
komplexer sind. Einführend ein kleines Beispiel zur Verwendung
von Referenzen. Komplexere Beispiele werden folgen. Normalerweise
ist es nicht möglich, mehrere Arrays einem Array zuzuweisen.
z.B.:
@banane=("Maier ","Müller ","Schulze ","Schmidt ");
@pampelmuse=("machen ","jede ","Scheisse ","mit");
(@Namen,@Spruch)=(@banane,@pampelmuse);
print @Namen;
Man
würde erwarten, dass in den Array @Namen die Namen und
in den Array @Spruch der Spruch eingelesen wird. Das ist aber
nicht der Fall. Der Array Namen kriegt alles, in dem @Spruch
steht gar nichts mehr. Just try it!
@banane=("Maier ","Müller ","Schulze ","Schmidt ");
@pampelmuse=("machen ","jede ","Scheisse ","mit");
(@Namen,@Spruch)=(@banane,@pampelmuse);
print @Spruch;
Was
kommt hier raus? Nichts! Referenzen können hier die Erwartungen
erfüllen, nämlich den Array @banane in den Array
@Namen einlesen und den Array @pampelmuse in den Array @Spruch.
Siehe folgende Beispiele!
| Auf einen
Zeiger zugreifen |
|
@banane=("Es ","ist ","der ","Wahnsinn");
$zeiger=\@banane;
print $zeiger;
Et
voilà! Ein Zeiger auf den array @banane. Eine
Referenz wird also mit dem Querbalken (backslash) gebildet.
Was da rauskommt sieht so aus.
ARRAY(0x1765690)
Der Wert in der Klammer ist immer ein anderer. Davor steht
aber immer ARRAY (Hash etc.). Der Zeiger zeigt auf den Speicherplatz
des Rechners, wo der Array abgespeichert ist. Es stellt sich
die Frage, wie die Werte des ursprünglichen Arrays über
den Zeiger da wieder rausgefischt werden. Das heißt,
wie dereferenziert man den Zeiger?
@banane=("Es ","ist ","der ","Wahnsinn");
$zeiger=\@banane;
print $$zeiger[0]; Ergebnis!
Es
Alles was man mit einem Array machen kann, kann man auch mit
der Referenz auf den Array machen, wie die folgenden Beispiele
zeigen.
| Auf einen gesamten Array
zugreifen |
|
@banane=("Es ","ist ","der ","Wahnsinn");
$zeiger=\@banane;
foreach (@$zeiger)
{
print "$_ \n";
}
Ergebnis!
Es ist der Wahnsinn
Hier werden alle Werte des @banane über den Zeiger ausgelesen.
Das heißt, will man auf den gesamten Array zugreifen,
weil man eine Funktion ausführen will, die nur im Zusammenhang
mit der Gesamtheit Sinn macht, dann verwendet man. @$zeiger;
| Einem Array Werte zuweisen
|
|
Einem Array kann man über Referenzen auch
Werte zuweisen.
@banane=("Es ","ist ","der ","Wahnsinn");
$zeiger=\@banane;
push(@$zeiger,".Nicht? ");
foreach (@$zeiger)
{
print "$_ \n";
}
Ergebnis!
Es ist der Wahnsinn .Nicht?
| Alternative Möglichkeiten,
um auf einzelne Elemente eines Arrays zuzugreifen
|
|
Es gibt drei Möglichkeiten, um auf das
erste Element des Arrays @banane zuzugreifen.
Dies zeigen die folgenden Beispiele.
In allen drei Fällen ist das Ergenis:
Es
@banane=("Es ","ist ","der ","Wahnsinn");
$zeiger=\@banane;
print $$zeiger[0];
erste
Variante
@banane=("Es ","ist ","der ","Wahnsinn");
$zeiger=\@banane;
print $zeiger->[0];
zweite
Variante
@banane=("Es ","ist ","der ","Wahnsinn");
$zeiger=\@banane;
print ${$zeiger}[0];
dritte
Variante
Um auf das erste Element des Arrays @banane zuzugreifen haben
wir also drei Möglichkeiten:
$$zeiger[0];
${$zeiger}[0];
$zeiger->[0];
Mit assoziativen Arrays, Variablen und Subroutinen läuft
das Verfahren völlig parallel.
%banane=("SPD"=>"Gerhard Schröder","Grüne"=>"Joschka Fischer","CDU"=>
"Angela Merkel","FDP"=>"Guido Westerwelle");
$zeiger=\%banane;
print $zeiger;
Was erhalten wir? HASH(0x1765678) - ein Zeiger
auf den Speicherplatz ist, wo der Hash geparkt wurde.
Die Dereferenzierung erfolgt wie oben.
%banane=("SPD"=>"Gerhard Schröder","Grüne"=>"Joschka Fischer","CDU"=>
"Angela Merkel","FDP"=>"Guido Westerwelle");
$zeiger=\%banane;
print $$zeiger{'SPD'};
Ergebnis!
Gerhard Schröder
| Auf einen gesamten Hash zugreifen
|
|
Will man auf den ganzen Hash über eine
Referenz zugreifen, sieht das so aus.
%banane=("SPD"=>"Gerhard Schröder","Grüne"=>"Joschka Fischer","CDU"=>
"Angela Merkel","FDP"=>"Guido Westerwelle");
$zeiger=\%banane;
foreach (keys(%$zeiger))
{
print "Schlüssel ist $_ und Wert dazu $$zeiger{$_} \n";
}
Ergebnis!
Schlüssel ist SPD und
Wert dazu Gerhard Schröder ect.
| Einem Array Werte zuweisen
|
|
Wir können dem HASH auch über eine
Referenz Werte zuweisen.
%banane=("SPD"=>"Gerhard Schröder","Grüne"=>"Joschka Fischer","CDU"=>
"Angela Merkel","FDP"=>"Guido Westerwelle");
$zeiger=\%banane;
$$zeiger{'PDS'}="Claudia Zimmer";
print $$zeiger{'PDS'};
Ergebnis!
Claudia Zimmer
| Alternative Möglichkeiten,
um auf einzelne Werte eines Hashs zuzugreifen
|
|
Auch bei Hashes gibt es die schon bei Arrays
beschriebenen Varianten des Zugriffs.
Um auf den Wert des ersten Schlüssels von %banane zuzugreifen
haben wir folgende drei Möglichkeiten:
%banane=("SPD"=>"Gerhard Schröder","Grüne"=>"Joschka Fischer","CDU"=>
"Angela Merkel","FDP"=>"Guido Westerwelle");
$zeiger=\%banane;
print $zeiger->{'SPD'};
%banane=("SPD"=>"Gerhard Schröder","Grüne"=>
"Joschka Fischer","CDU"=>"Angela Merkel","FDP"=>"Guido Westerwelle");
$zeiger=\%banane;
print ${$zeiger}{'SPD'};
%banane=("SPD"=>
"Gerhard Schröder","Grüne"=>"Joschka Fischer","CDU"=>"Angela Merkel","FDP"=>"Guido Westerwelle");
$zeiger=\%banane;
print $$zeiger{'SPD'};
Wir erhalten also mutatis mutandis wieder die
drei Möglichkeiten der Dereferenzierung, die wir bei
Arrays schon hatten.
$$zeiger{'SPD'};
${$zeiger}{'SPD'};
$zeiger->{'SPD'};
Mit Zeigern kann man natürlich auch auf
Variablen zugreifen.(\$)
$banane="Die Kuh die auf der Weide steht, sie träumt von einem Salat so schön";
$zeiger=\$banane;
print "$zeiger \n";
print "$$zeiger \n";
Anonymous Arrays/Hashs
sind Arrays bzw. Hashs, die keinen Namen haben und nur über
einen Zeiger angesprochen werden können.
$zeiger=["Man ","muss ","das ","Chaos
","in ","sich ","tragen ","um ","einen ","Stern ","zu ","gebären
"];
print $$zeiger[9];
Was kommt da raus?
Stern
Wie deutlich zu sehen, hat der Array keinen Namen, sondern
nur einen Zeiger. Das heißt, die einzelnen Elemente
dieses Arrays können nur über einen Zeiger angesprochen
werden. Anonymous Arrays haben keinen Namen und werden mit
eckigen Klammern [ ] geschrieben.
Ähnlich sieht es bei den anonymous Hashs aus:
$zeiger={"Indien"=>"Neu Delhi","Iran"=>"Teheran","Russland"=>"Moskau","Frankreich"=>"Paris"};
print $$zeiger{'Iran'};
Was kommt da raus?
Teheran
Wie auch hier deutlich zu erkennen ist, hat der anonymous
Hash keinen Namen. Gebildet wird er mit derngeschweiften Klammern
{ }.
Schreiten wir voran zum grossen Show down: zur Bildung
mehrdimensionaler Arrays über Referenzen.
@menue=(["Kartoffeln","Sauerbraten","Preiselbeeren"],["Yoghurt","Obst"],
["Cognac","Apfelsaft","Kaffee"]);
print $menue[1][1];
Das
ist jetzt nicht mehr so einfach? Ich verrate es. Obst
kommt raus. $menue[1] ist ein Zeiger auf einen Array, genau
wie $menue[0] und $menue[2]. Von dem angesprochenen Array
(Yoghurt, Obst), suchen wir das Element mit dem Index 1, also
das Obst.
Zwei weitere mögliche Schreibweisen (bereits oben beschrieben):
@menue=(["Kartoffeln","Sauerbraten","Preiselbeeren"],["Yoghurt","Obst"],
["Cognac","Apfelsaft","Kaffee"]);
print ${$menue[1]}[1];
@menue=(["Kartoffeln","Sauerbraten",
"Preiselbeeren"],["Yoghurt","Obst"], ["Cognac","Apfelsaft","Kaffee"]);
print $menue[1]->[1];
Mit Hashs sieht dies folgendermaßen
aus:
@menue=(
{'Maier'=>'Ernst','Ehmann'=>'Andres','Müller'=>'Peter'},
{'Maier'=>'030-454567','Ehmann'=>'030-47301388','Müller'=>'030-45345476'},
{'Maier'=>'Briefmarken sammeln','Ehmann'=>'dösen','Müller'=>'mit dem grossen Zeh wackeln'}
);
print $menue[2]{'Müller'};
Wenn es den Müller nur einmal gäbe,
wäre es einfach. Den gibt es aber dreimal. Also raten
kann man nicht. Es kommt raus: mit
dem großen Zeh wackeln. $menue[2] ist ein Zeiger
auf den dritten Array, der die Hobbys abspeichert. Davon wollen
wir das Hobby mit dem Schlüssel Müller haben.
In den alternativen Schreibweisen, sieht das dann so aus:
@menue=(
{'Maier'=>'Ernst','Ehmann'=>'Andres','Müller'=>'Peter'},
{'Maier'=>'030-454567','Ehmann'=>'030-47301388','Müller'=>'030-45345476'},
{'Maier'=>'Briefmarken sammeln','Ehmann'=>'dösen','Müller'=>'mit dem grossen Zeh wackeln'}
);
print ${$menue[2]}{'Müller'};
@menue=(
{'Maier'=>'Ernst','Ehmann'=>'Andres','Müller'=>'Peter'},
{'Maier'=>'030-454567','Ehmann'=>'030-47301388','Müller'=>'030-45345476'},
{'Maier'=>'Briefmarken sammeln','Ehmann'=>'dösen','Müller'=>'mit dem grossen Zeh wackeln'}
);
print $menue[2]->{'Müller'};
Im eigentlichen Sinne wird kein zweidimensionaler
Array gebildet, da der zweite Array keine Untereinteilung
des ersten ist. Mit diesem Verfahren lässt sich aber
leicht das gleiche erreichen. In letzter Konsequenz ist dieser
Ansatz leistungsfähiger, insbesondere auch deswegen,
weil man Konstrukte bauen kann, bei denen alle möglichen
Typen von Variablen, Arrays, Hashs, Skalarvariablen miteinander
verknüpft sein können.
@banane=(
{"Goethe"=>"1749","Schiller"=>"1759","Thomas Mann"=>"1875"},
["Torquato Tasso","Wallenstein","Der Zauberg"],
{"Goethe"=>"1833","Schiller"=>"1805","Thomas Mann"=>"1956"},
["Frankfurt am Main","Ludwigsburg","Lübeck"]
);
print "Goethe wurde ". $banane[0]{'Goethe'}." in ".$banane[3][0]. " geboren. Ein Werk der Klassik ist ". $banane[1][0];
Was kommt raus?
Goethe wurde 1749 in Frankfurt
am Main geboren. Ein Werk der Klassik ist Torquato Tasso
In den zwei alternativen Schreibweisen sieht das dann so aus:
@banane=(
{"Goethe"=>"1749","Schiller"=>"1759","Thomas Mann"=>"1875"},
["Torquato Tasso","Wallenstein","Der Zauberg"],
{"Goethe"=>"1833","Schiller"=>"1805","Thomas Mann"=>"1956"},
["Frankfurt am Main","Ludwigsburg","Lübeck"]
);
print "Goethe wurde ". ${$banane[0]}{'Goethe'}." in ".${$banane[3]}[0]. " geboren. Ein Werk der Klassik ist ". ${$banane[1]}[0];
@banane=(
{"Goethe"=>"1749","Schiller"=>"1759","Thomas Mann"=>"1875"},
["Torquato Tasso","Wallenstein","Der Zauberg"],
{"Goethe"=>"1833","Schiller"=>"1805","Thomas Mann"=>"1956"},
["Frankfurt am Main","Ludwigsburg","Lübeck"]
);
print "Goethe wurde ". $banane[0]->{'Goethe'}." in ".$banane[3]->[0]. " geboren. Ein Werk der Klassik ist ". $banane[1]->[0];
| Anzeigen, auf was der Zeiger zeigt - Die
Funktion ref. |
|
Komplizierter wird es, wenn man alle Werte innerhalb einer foreach
Schleife auslesen will. Da Arrays anders aufgeknackt werden
als Hashs braucht man eine Möglichkeit um herauszufinden,
auf was der Zeiger eigentlich zeigt. Das passiert mit der Funktion
ref.
@banane=(
{"Goethe"=>"1749","Schiller"=>"1759","Thomas Mann"=>"1875"},
["Torquato Tasso","Wallenstein","Faust"],
{"Goethe"=>"1833","Schiller"=>"1805","Thomas Mann"=>"1956"},
["Frankfurt am Main","Ludwigsburg","Lübeck"]
);
print "Zuerst kommt ein ". ref($banane[0]). " dann ein ". ref($banane[1]). " dann ein ". ref($banane[2]) . " und schluss endlich ein ". ref($banane[3]);
Der Skript zeigt dann "Zuerst
kommt ein HASH dann ein ARRAY dann ein HASH und schluss endlich
ein ARRAY".
Beispielhaft soll hier einmal der ganze Array @banane ausgelesen
werden. In einem real live Beispiel, müsste man wohl
dafür sorgen, dass das Konstrukt an sich geeignet ist.
@banane=(
{"Goethe"=>"1749","Schiller"=>"1759","Thomas Mann"=>"1875"},
["Torquato Tasso","Wallenstein","Faust"],
);
foreach $himbeere(@banane)
{
if(HASH eq ref($himbeere))
{
foreach (keys(%$himbeere))
{
print "$_ wurde ${$himbeere}{$_} geboren \n";
}
}
if (ARRAY eq ref($himbeere))
{
foreach (@$himbeere)
{
print "$_ ist ein wichtiges Werk der deutschen Klassik \n";
}
}
}
| Arrays mit Zeigern auf anonymous Arrays/-Hashs
|
|
Man kann auch einen Array basteln, der nichts
anderes enthält als Zeiger, die wiederum auf anonyme
Arrays bzw. anonyme Hashs zeigen. Das machen wir jetzt noch!
@banane=(["Karotte","Tomate","Kapern","Rettich"],["Käse","Yoghurt","Buttermilch"],
{"Italien"=>"Dante Alighieri","Frankreich"=>"Victor Hugo"});
@pampelmuse=({"Baden-Württemberg"=>"Stuttgart","Hessen"=>"Wiesbaden",
"Schleswig-Holstein"=>"Kiel"},["Sachen","gibt","es"]);
@superbanane=(\@banane,\@pampelmuse);
print $superbanane[0];
Die $superbanane[0] ist jetzt ein Zeiger auf
den Array @banane.
Will man jetzt z.B. auf die Kapern und auf Stuttgart zugreifen,
dann sieht das so aus.
@banane=(["Karotte","Tomate","Kapern","Rettich"],["Käse","Yoghurt","Buttermilch"],
{"Italien"=>"Dante Alighieri","Frankreich"=>"Victor Hugo"});
@pampelmuse=({"Baden-Württemberg"=>"Stuttgart","Hessen"=>"Wiesbaden",
"Schleswig-Holstein"=>"Kiel"},["Sachen","gibt","es"]);
@superbanane=(\@banane,\@pampelmuse);
print $$superbanane[0][0][2]."\n";
print $$superbanane[1][0]{'Baden-Württemberg'};
In der alternativen Schreibweise sieht das so
aus.
@banane=(["Karotte","Tomate","Kapern","Rettich"],["Käse","Yoghurt","Buttermilch"],
{"Italien"=>"Dante Alighieri","Frankreich"=>"Victor Hugo"});
@pampelmuse=({"Baden-Württemberg"=>"Stuttgart","Hessen"=>"Wiesbaden",
"Schleswig-Holstein"=>"Kiel"},["Sachen","gibt","es"]);
@superbanane=(\@banane,\@pampelmuse);
print ${${$superbanane[0]}[0]}[2]. "\n";
print ${${$superbanane[1]}[0]}{'Baden-Württemberg'}."\n";
Das am besten nochmal step by step.
$superbanane[0] => ist der Zeiger auf den Array @banane.
${$superbanane[0]}[0] => ist der Zeiger auf das den
ersten anonymen Array von @banane,
${${$superbanane[0]}[0]}[2] => ist das dritte Element
des ersten anonymen Arrays, der in dem Array @banane steckt.
Und dann gibt es, wie oben beschrieben, noch
diese Schreibweise.
@banane=(["Karotte","Tomate","Kapern","Rettich"],["Käse","Yoghurt","Buttermilch"],
{"Italien"=>"Dante Alighieri","Frankreich"=>"Victor Hugo"});
@pampelmuse=({"Baden-Württemberg"=>"Stuttgart","Hessen"=>"Wiesbaden",
"Schleswig-Holstein"=>"Kiel"},["Sachen","gibt","es"]);
@superbanane=(\@banane,\@pampelmuse);
print $superbanane[0]->[0]->[2] . "\n";
print $superbanane[1]->[0]->{'Baden-Württemberg'}."\n";
Was haben wir gelernt? Perl hat zwar keine mehrdimensionalen
Arrays im eigentlichen Sinne, aber mit Referenzen lassen sich
diese nachbauen, bzw. es ist möglich sogar Konstrukte
beliebiger Komplexität zusammenzubauen. Gebraucht werden
Referenzen insbesondere anonyme Hashs und anonyme Arrays in
der objektorientierten Programmierung. Darüber hinaus
arbeitet Perl intern sehr oft mit Referenzen. Die Aussage
allerdings, die man manchmal antrifft, dass man Perl ohne
ein Verständnis von Referenzen nicht nutzen kann, ist
nicht zutreffend.
|
 |