Beispiele:
#!/usr/local/bin/perl -w $nr = 42; $ref_nr = \$nr; @planeten = ( 'Erde', 'Mars', 'Jupiter' ); $ref_planeten = \@planeten; %tiere = ( 'Tiger' => 'Indien', 'Löwe' => 'Afrika' ); $ref_hash = \%tiere; |
Wie man sieht, wird eine Referenz einfach dadurch erzeugt, daß
vor die Variable ein Backslash ("\
") gesetzt
wird. Unabhängig davon, von welchem Typ das referenzierte
Objekt ist, ist die Referenz immer ein Skalar - sie besitzt
also die Form $
name.
Um von einer Referenz wieder zurück zur referenzierten Variablen zu kommen ("Dereferenzierung"), stellt man der Referenz das Symbol voran, das dem Typ des referenzierten Objekts entspricht.
Beispiele:
#!/usr/local/bin/perl -w $nr = 42; $ref_nr = \$nr; $deref_nr = $$ref_nr; @planeten = ( 'Erde', 'Mars', 'Jupiter' ); $ref_planeten = \@planeten; @deref_planeten = @$ref_planeten; %tiere = ( 'Tiger' => 'Indien', 'Löwe' => 'Afrika' ); $ref_tiere = \%tiere; %deref_tiere = %$ref_tiere; |
Hier muß man also den jeweiligen Datentyp beachten!
(De-)Referenzierung kann auch beliebig mehrstufig angewandt werden:
#!/usr/local/bin/perl -w $stern = 'Sirius'; $ref_ref_ref_stern = \\\$stern; $stern = $$$$ref_ref_ref_stern; |
Auch Elemente eines Arrays lassen sich (de-)referenzieren:
#!/usr/local/bin/perl -w @zahlen = ( 'null', 'eins', 'zwei', 'drei' ); $ref_zahlen = \@zahlen; print $$ref_zahlen[2]."\n"; $ref_zwei = \$zahlen[2]; print $$ref_zwei."\n"; |
Im ersten Teil wird hier eine Referenz auf das Array als Ganzes erstellt.
Sie wird dann dereferenziert ($$ref_zahlen
) und von dem Ergebnis
(dem Array) das Element mit dem Index 2 ausgewählt. Im zweiten Teil
wird dagegen eine Referenz nur eines einzelnen Elements des Arrays erzeugt
und wieder dereferenziert.
Ersteres beschreibt den Mechanismus, den Perl für gewöhnliche Variablen benutzt, bei dem die Werte (values) der Argumente an das Unterprogramm übergeben werden. Dies bedeutet, daß die lokalen Variablen, denen die Argumente zugewiesen werden, völlig unabhängig von den Variablen existieren, die die Argumente beim Aufruf bestimmen.
Manchmal möchte man aber eine Variable in einem Unterprogramm manipulieren, d.h., etwaige Operationen, die im Rumpf der Subroutine durchgeführt werden, sollen sich auch auf die Variablen im aufrufenden Programmteil auswirken. Eine Möglichkeit besteht darin, die manipulierten Variablen als Rückgabewerte an den aufrufenden Programmteil zu übergeben.
Eleganter und effektiver geht es aber mit Referenzen ("call by reference"). Übergibt man eine Referenz als Argument, so zeigt die (lokale) Referenz auf die Variable im Argument und kann sie direkt bearbeiten.
#!/usr/local/bin/perl -w sub gross_1 { ### einfacher "call by value" my $s = $_[0]; $s = ucfirst($s); } sub gross_2 { ### "call by value" mit Rückgabewert my $s = $_[0]; $s = ucfirst($s); return($s); } sub gross_3 { ### Übergabe einer Referenz my $ref_s = $_[0]; $$ref_s = ucfirst($$ref_s); } sub gross_4 { ### Sonderfall @_ $_[0] = ucfirst($_[0]); } print "1) ".($wort = 'kamel')." -> "; gross_1($wort); print "$wort\n"; print "2) ".($wort = 'kamel')." -> "; $wort = gross_2($wort); print "$wort\n"; print "3) ".($wort = 'kamel')." -> "; gross_3(\$wort); print "$wort\n"; print "4) ".($wort = 'kamel')." -> "; gross_4($wort); print "$wort\n"; |
1) kamel -> kamel 2) kamel -> Kamel 3) kamel -> Kamel 4) kamel -> Kamel |
Wie man sieht, wirkt sich im ersten Aufruf die Manipulation in
"gross_1
" nicht auf die globale Variable "$wort
"
aus. "gross_2
" zeigt, wie sich das Problem über
den Rückgabewert lösen läßt. In
"gross_3
" wird eine Referenz übergeben, mit
Hilfe derer die globale Variable verändert werden kann.
Das vierte Beispiel zeigt, daß das spezielle Array @_
,
das die Unterprogrammparameter enthält, nicht wirklich aus
Kopien der übergebenen Variablen besteht. Verändert
man die Elemente von @_
, so wirkt sich dies auch auf die
Variablen der Parameter im aufrufenden Programmteil aus. Dieser Trick
sollte aber aus Gründen der Übersichtlichkeit nicht
unbedingt genutzt werden - er stammt aus der Zeit, als es
in Perl noch keine Referenzen gab.
#!/usr/local/bin/perl -w sub hallo { return "Hallo, $_[0]!" }; $ref_sub = \&hallo; print &$ref_sub('Welt')."\n"; |
Hallo, Welt! |
Bei der Bildung der Referenz ist darauf zu achten, daß sie
durch Voranstellen eines Backslashes vor den Namen des Unterprogramms
mit dem "&
" erfolgt. Es dürfen dabei keine
Klammern oder gar Argumente angehängt werden (in diesem Falle
würde eine Referenz auf den Rückgabewert der Routine
gebildet werden). Auch darf das "&
" nicht weggelassen
werden. Analog zur Dereferenzierung bei Variablen muß der
Typ des Objektes durch Angabe des entsprechenden Symbols (hier:
"&
") vermerkt werden.
Will man ein Unterpogramm nur über eine Referenz aufrufen, bietet sich eine sogenannte anonyme Subroutine an. Sie besitzt keinen eigenen Namen und liefert bei der Definition eine Referenz auf den Programmcode zurück.
Beispiel:
#!/usr/local/bin/perl -w $ref_sub = sub { return "Hallo, $_[0]!" }; print &$ref_sub('Welt')."\n"; |
Man beachte hierbei zwei Dinge: zum einen hat das Unterprogramm, wie
schon erwähnt, keinen Namen. Daher folgt unmittelbar auf das
Schlüsselwort "sub
" die Definition in
geschweiften Klammern. Außerdem darf nicht übersehen werden,
daß es sich hierbei um eine Zuweisung handelt, die durch
ein Semikolon abgeschlossen werden muß (es sei denn, diese
Zeile steht beispielsweise am Ende eines Blockes).
Referenzen können genauso wie andere skalare Größen als Rückgabewerte von Subroutinen auftreten; d.h., ein Unterprogramm kann eine Referenz auf ein anderes Unterprogramm liefern.
Beispiel:
#!/usr/local/bin/perl -w sub master { my $ref_sub; $ref_sub = sub { print "Hallo!\n" }; return($ref_sub); } $ref_hallo = master(); &$ref_hallo; |
Hallo! |
Ein besonderer Fall in diesem Zusammenhang sind sogenannte "Closures".
Dabei betrachtet man Unterprogramme mit lokalen Variablen (deklariert
durch my
). Die genannten lokalen Variablen werden bei
der Definition und Zuweisung zu einer Referenz sozusagen mit
eingeschlossen.
Beispiel:
#!/usr/local/bin/perl -w sub hallo { my $planet = $_[0]; my $ref = sub { print "Hallo, $planet!\n" }; return($ref); } $ref_erde = hallo('Erde'); $ref_mars = hallo('Mars'); &$ref_erde; &$ref_mars; |
Hallo, Erde! Hallo, Mars! |
Das Bemerkenswerte daran ist, daß zu dem Zeitpunkt, an dem
die anonyme Subroutine ausgeführt wird (hier: am Ende des
Skripts), eigentlich der Gültigkeitsbereich der lokalen
Variablen $planet
schon längst verlassen
worden ist. Dennoch "erinnern" sich noch beide Referenzen
an den lokalen Wert, der zum Zeitpunkt ihrer Zuweisung gültig war.
Autor: Eike Grote | Letzte Änderung: 22.08.1999 |