Referenzen
Harte Referenzen
Sogenannte "harte" Referenzen sind skalare Größen, die
auf eine beliebige Variable "zeigen". Das Ziel kann dabei eine
einfache skalare Variable sein, aber auch ein Array oder Hash oder
auch ein Unterprogramm. Auch kann man eine Referenz auf eine
Referenz erstellen.
Beispiele:
#!/usr/local/bin/perl -w
use strict;
my $nr = 42; my $ref_nr = \$nr;
my @planeten = ( 'Erde', 'Mars', 'Jupiter' ); my $ref_planeten = \@planeten;
my %tiere = ( 'Tiger' => 'Indien', 'Löwe' => 'Afrika' ); my $ref_hash = \%tiere;
|
|
Wie man sieht, wird eine Referenz einfach dadurch erzeugt, daß
vor die zu referenzierende 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
use strict;
my $nr = 42; my $ref_nr = \$nr; my $deref_nr = $$ref_nr;
my @planeten = ( 'Erde', 'Mars', 'Jupiter' ); my $ref_planeten = \@planeten; my @deref_planeten = @$ref_planeten;
my %tiere = ( 'Tiger' => 'Indien', 'Löwe' => 'Afrika' ); my $ref_tiere = \%tiere; my %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
use strict;
my $stern = 'Sirius';
my $ref_ref_ref_stern = \\\$stern;
$stern = $$$$ref_ref_ref_stern;
|
|
Auch Elemente eines Arrays lassen sich (de-)referenzieren:
#!/usr/local/bin/perl -w
use strict;
my @zahlen = ( 'null', 'eins', 'zwei', 'drei' );
my $ref_zahlen = \@zahlen; print $$ref_zahlen[2]."\n";
my $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.
[Seitenanfang]
"Call by Reference"
Bei dem Aufruf von Unterprogrammen unterscheidet man
im wesentlichen zwei Typen, was die Behandlung der Argumente betrifft:
"call by value"
und "call by reference".
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
use strict;
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) ".(my $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.
[Seitenanfang]
Referenzen auf Unterprogramme
Auch Referenzen auf Subroutinen sind möglich:
#!/usr/local/bin/perl -w
use strict;
sub hallo { return "Hallo, $_[0] !" };
my $ref_sub = \&hallo;
print &$ref_sub('Welt')."\n";
|
|
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 Unterprogramm 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
use strict;
my $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 Blocks).
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
use strict;
sub master { my $ref_sub; $ref_sub = sub { print "Hallo !\n" }; return($ref_sub); }
my $ref_hallo = master();
&$ref_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
use strict;
sub hallo { my $planet = $_[0]; my $ref = sub { print "Hallo, $planet !\n" }; return($ref); }
my $ref_erde = hallo('Erde'); my $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.
[Seitenanfang]