In Perls Objektorientierter Programmierung spielen Referenzen eine wesentliche Rolle
In Perl kann eine Referenz nur zusammen mit dem abstrakten Datentyp erzeugt werden, z.B. wenn die Variable oder Subfunktion definiert wird (Stand Perl v5.16) oder bereits als Variable oder Subfunktion vorliegt, Beispiele:
# Blanko Referenzen die später mit Werten # befüllt werden können my $href = {}; # Hashreferenz my $aref = []; # Arrayreferenz # Die Funktion liefert ein Array # untenstehend wird gleich eine Referenz # auf das Array erzeugt my $loc = [localtime];
Als abstrakte Datentypen werden Array's und Hashes verstanden.
Ein der Variablen vorangestellter Backslash erzeugt die Referenz:
# Referenz auf den Hash %ENV my $env = \%ENV; # Erzeuge eine Referenz auf ein Array my @arr = qw(Anton Berta Cäsar); my $aref = \@arr; # Referenz auf ein Scalar my $name = "Dankwart"; my $nref = \$name;
Dereferenzieren erfolgt entsprechend Scalar, Hash oder Array mit $
, %
oder @
:
print "@$aref"; # Anton Berta Cäsar print $$nref; # Dankwart print join "\n", keys %$env;
Das war die Pflicht, jetzt kommt die Kür:
# Erzeuge eine Hashreferenz my $href = { name => "Dankwart", plz => 55099, env => { temp => "20°C", hygr => "99%", }, }; # zugriff! print $href->{name}; print $href->{env}->{temp}; # wobei der erste Pfeil genügt print $href->{env}{temp}; # Achtung Klammer setzen! print join "\n", keys %{$href->{env}}; # localtime liefert ein Array # in [] aufgerufen erhalten wir # gleich die Referenz auf das Array my $loc = [localtime]; # ein einzelnes Element ausgeben # verwende den Pfeil-Operator print $loc->[8]; # is dst 1 oder 0
Der Vorteil in der Verwendung von Referenzen auf Variablen besteht darin, dass es die Originaldaten nur einmal gibt im Hauptspeicher, d.h. damit werden Inkonsistenzen vermieden. Einen besonders hohen Stellenwert haben Hashreferenzen, weil damit viele einzelne Variablen kompakt zusammengefasst werden können und auf diese außerdem namentlich direkt zugegriffen werden kann.
Code-Referenzen werden mit dem Schlüsselwort sub
erzeugt:
# Erzeuge eine Referenz auf eine Funktion my $coderef = sub{ print "Hallo @_!"; }; # Semikolon nicht vergessen! # Rufe die Funktion über die Referenz auf $coderef->(1,2,3); # Ausgabe: Hallo 1 2 3!
Das Beispiel zeigt auch, wie in diesem Fall die Argumente übergeben werden.
Eine Instanz einer Klasse ist nichts weiter als eine Referenz, die weiß zu welcher Klasse sie gehört -- so schreibt es Eric Foster-Johnson. Betrachte den Code untenstehend:
my $m = bless{}, 'main';
So ist $m
eine Hashreferenz, die mit dem Namen der Klasse main
gesegnet ist. Gleichermaßen ist $m
eine Instanz der Klasse main
und mit dieser Instanz lassen sich Funktionen sowie Codereferenzen innerhalb der gleichen Klasse aufrufen:
# Erzeuge eine Referenz auf eine Funktion my $coderef = sub{ my $self = shift; print "Hallo @_!"; }; # Semikolon nicht vergessen! # Instanz der Klasse main erzeugen my $m = bless{}, 'main'; # Rufe die Coderef über die Instanz der Klasse main auf # Der Pfeil-Operator übergibt die aufrufende Instanz $m->$coderef(1,2,3); # Hallo 1 2 3! # Dasselbe nur anders notiert $coderef->($m,1,2,3); # Hallo 1 2 3!
package AnyClass; # eine ganz normale Deklaration sub foo{ my $self = shift; my $class = ref $self; print "Hallo @_ in Klasse $class!"; } # Instanz der aktuellen Package my $m = bless{}, __PACKAGE__; # Prüfe ob es die Funktion/Methode gibt my $coderef = $m->can('foo') or die "Kein Code für Funktion 'foo'"; # Methode ausführen $m->$coderef(1,2,3); # Hallo 1 2 3 in Klasse AnyClass!
Die Package package main;
gibt es praktisch immer, auch wenn sie nicht explizit so deklariert ist. Der Code obenstehend deklariert die Klasse main
kurzerhand um nach AnyClass
. Unabhängig davon, beinhaltet __PACKAGE__
stets den voll qualifizierten Namen derjenigen Package in welcher die Notation erfolgte. Die Funktion can()
ist eine Methode, die von der Klasse UNIVERSAL
geerbt wird, von dieser Klasse erbt jede in Perl erstellte Package (Klasse) und natürlich auch die Package main
oder AnyClass
. Soweit die gesuchte Funktion/Methode im aktuellen Namensraum existiert, liefert can()
eine Referenz auf diese. Schließlich ermittelt die Funktion ref()
den Namen derjenigen Klasse mit welcher die Instanz gesegnet wurde.
Ab hier kommen ein paar Anregungen aus meiner langjährigen Praxis. Zunächst eine Betrachtung zu den sogenannten Typeglobs, ein Stückchen Code sagt mehr als 1,000 Worte:
# Erzeuge eine Typeglob *foo = sub{ print "Hallo @_!" }; # type means sub # und so funktioniert der Aufruf foo(1,2,3); # Hallo 1 2 3!
Als Nächstes einen Typeglob auf ein Handle, siehe Code untenstehend:
# Argument soll ein Handle sein sub read_handle{ my $handle = shift; while( read( $handle, my $buffer, 1024) ){ print $buffer; } }; # Anders kann das Handle # gar nicht übergeben werden read_handle(DATA); # erzeugt Fehlermeldung! read_handle(*DATA); # so funktioniert es __DATA__ asdf.... blah-Texte usw.
Über den Umweg eines Typeglob sind auch Zuweisungen wie my $handle = *STDIN;
möglich, wird der *
(Glob-Operator) nicht notiert, erscheint eine Fehlermeldung, weil es dem Perl-Interpreter in diesem Kontext nicht möglich ist, ein Handle als Type zu erkennen. Wahrend Typeglobs auch mit Array- und Hashreferenzen möglich sind, werden Globs auf Funktionen häufiger verwendet, z.B. um Funktionen mit mehreren verschiedenen Namen zu klonen oder Referenzen auf Funktionen zu erzeugen:
sub foo{ print "This is foo" } *bar = *foo; bar(); # This is foo # Referenz auf sub über TypeGlob erzeugen my $ref = *foo; # Funktion über Code-Ref aufrufen $ref->(); # This is foo
Perl versteht als Scalar nicht nur das, was mit einem $
beginnt, sondern auch Referenzen. Wobei es unerheblich ist, ob Referenzen auf Arrays oder Hashes verweisen oder wiederum auf Scalare. Als Schlüssel in einem Hash wird ein String erwartet, daher können Stringbegrenzer auch entfallen die den CODE ohnehin nicht leslicher machen. Der Wert zu einem Hash-Schlüssel jedoch ist grundsätzlich ein Scalar, das kann ein String sein oder aber auch eine Referenz. Allein dieser Fakt ermöglicht tiefergehende Datenstrukturen, die ohne Referenzen also gar nicht möglich wären!
Wie bereits weiter oben festgestellt: Klasseninstanzen sind Referenzen die mit dem Namen der Klasse gesegnet sind. Dieses Segnen (bless) ist nur Referenzen vorbehalten, wobei die Instanz einer Klasse nicht unbedingt eine Referenz auf einen Hash sein muss, ja, es darf auch eine Referenz auf ein Array oder auf ein Scalar sein oder auf ein FileHandle! Für welche Art von Referenz man sich entscheidet, hängt ganz von der konkreten Aufgabenstellung ab.
In der Mehrzahl aller Anwendungsfälle ist eine Klasseninstanz eine Referenz auf einen Hash, wobei Schlüssel in diesem Hash selbstverständlich auch Arrays referenzieren und Array-Elemente wiederum Hashreferenzen sind:
my $self = bless{ numbers => [1,2,3,4], slice => [{},{},{}], }, $class;
Eric Foster Johnson: "Perl Module" Verlag mitp, ISBN 3-8266-0570-5
Datenschutzerklärung: Diese Seite dient rein privaten Zwecken. Auf den für diese Domäne installierten Seiten werden grundsätzlich keine personenbezogenen Daten erhoben. Das Loggen der Zugriffe mit Ihrer Remote Adresse erfolgt beim Provider soweit das technisch erforderlich ist. sos@rolfrost.de.