Just another Perl shrine | |
PerlMonks |
(ASCII Grafik in Anlehnung an PEGS (PErl Graphical Structures) von Joseph Hall)
Was ist eine Referenz?
Es gibt zwei Arten von Referenzen: 'harte' und 'weiche'. Die 'weichen' werden auch 'symbolische' genannt und werden hier nicht weiter behandelt.
Eine Referenz ist eine Art Zeiger auf einen Wert:
+-----------+ +-----------+ | O-----+----->| 12345 | +-----------+ +-----------+
+----------\ +----------\ | a > | b > +----------/ +----------/ | | +-----------+ +-----------+ | O-----+----->| 12345 | +-----------+ +-----------+
+----------\ | b > +----------\ +----------/ | a > | +----------/ +-----------+ | | O-----+----->+###########+ +-----------+ +"""""""""""+ | Foo | +----------\ +-----------+ | c > | Bar | +----------/ +-----------+ | | Baz | +-----------+ +-----------+ | O-----+----->| Qux | +-----------+ +-----------+
Eine Referenz auf eine Liste, die Referenzen auf Listen enthält.+----------\ | a > +-->+###########+ +----------/ | +"""""""""""+ | | | Foo | +-----------+ | +-----------+ | O-----+----->+###########+ | | Bar | +-----------+ +"""""""""""+ | +-----------+ | O-----+---+ +-----------+ | O-----+------>+###########+ +-----------+ +"""""""""""+ | O-----+---+ | Baz | +-----------+ | +-----------+ | | Qux | | +-----------+ | | +-->+###########+ +"""""""""""+ | Baz | +-----------+
Ein Hash, das Referenzen auf Listen enthält.+----------\ | a > +-->+###########+ +----------/ | +"""""""""""+ | | | Foo | +#########################+ | +-----------+ +"""""""""""""""""""""""""+ | | Bar | +-----------\ +-----------+ | +-----------+ | aaa >| O-----+---+ +-----------< +-----------+ | bbb >| O-----+------>+###########+ +-----------< +-----------+ +"""""""""""+ | ccc >| O-----+---+ | Baz | +-----------/ +-----------+ | +-----------+ | | Qux | | +-----------+ | | +-->+###########+ +"""""""""""+ | Baz | +-----------+
$cref = \12345 | Referenz auf eine Konstante |
$sref = \$s | Referenz auf den Wert von $s |
$aref = \@a | Referenz auf das Array @a |
$href = \%h | Referenz auf das Hash %h |
$fref = \&f | Referenz auf die Subroutine &f |
Eine Referenz auf ein anonymes Hash:$aref = [123, 456, 789];
Eine Referenz auf eine Anonyme Subroutine:$href = {NAME => 'Bernd', EMAIL => 'bdulfer@sybase.com'};
$fref = sub { print "AnonSub\n" };
(sinnloses :-) Beispiel:
Die Bedeutung von @$ wird weiter unten erklärt.use Data::Dumper; sub make_hash_from_arrays { my ($aref1, $aref2) = @_; my %hash; $hash{$_} = shift @$aref2 foreach (@$aref1); print Dumper(\%hash); } my @a = ('a', 'b', 'c', 'd'); my @b = (1, 2, 3, 4); make_hash_from_arrays(\@a, \@b);
Fall 2, komplexe Datenstrukturen:
Ein Adressbuch soll in einer Datenstruktur abgebildet werden.
Ohne Referenzen gäbe es folgende Möglichkeiten:
1. Eine Adresse wird mit Trennzeichen in ein Hashelement geschrieben. Um auf einzelne Daten zuzugreifen, wird split verwendet:
2. Die Adresse wird auf mehrere Hashes verteilt. Um eine Adresse zu drucken, werden einzelne Elemente aus verschiedenen Hashes benötigt:$adresse{Bernd} = 'Bernd Dulfer|Kapellenstr. 1|bdulfer@sybase.com' +; $email = (split(/\|/, $adresse{bernd}))[2];
$name{Bernd} = 'Bernd Dulfer'; $str{Bernd} = 'Kapellenstr. 1'; $email{Bernd} = 'bdulfer@sybase.com'; print_adresse($name{Bernd}, $str{Bernd});
Wenn zusätzlich zur Adresse auch noch eine Liste mit z.B. ausgeliehenen Büchern gespeichert werden soll, ist dies ohne Referenzen kaum noch zu handhaben. Mit Referenzen sieht es folgendermaßen aus:+----------\ | adresse > +----------/ | +#######################+ +"""""""""""""""""""""""+ +-----------\ +---------+ | Bernd >| O----+----->+##################################+ +-----------/ +---------+ +""""""""""""""""""""""""""""""""""+ +-----------\ +--------------------+ | Name >| Bernd Dulfer | +-----------< +--------------------+ | Str >| Kapellenstr. 1 | +-----------< +--------------------+ | EMail >| bdulfer@sybase.com| +-----------/ +--------------------+ $adresse{Bernd} = { Name => 'Bernd Dulfer', Str => 'Kapellenstr. 1', EMail => 'bdulfer@sybase.com' }; $email = $adresse{Bernd}->{EMail}; print_adresse($adresse{Bernd});
+----------\ | adresse > +----------/ | +##########+ +""""""""""+ +----\ +---+ |Bernd>| O-+->+###########################+ +----/ +---+ +"""""""""""""""""""""""""""+ +------\ +------------------+ |Name >|Bernd Dulfer | +------< +------------------+ |Str >|Kapellenstr. 1 | +------< +------------------+ |EMail >|bdulfer@sybase.com| +------< +------------------+ |Buecher>| O---------+->+#####################+ +------/ +------------------+ +"""""""""""""""""""""+ |Der Herr der Ringe | +---------------------+ |Per Anhalter durch...| +---------------------+ |Die Farben der Magie | +---------------------+ $adresse{Bernd} = { Name => 'Bernd Dulfer', Str => 'Kapellenstr. 1', EMail => 'bdulfer@sybase.com', Buecher => [ 'Der Herr der Ringe', 'Per Anhalter durch die Galaxie', 'Die Farben der Magie' ] };
Gibt :$s = 'qwertz'; $sref = \$s; print ${$sref}, "\n"; print $$sref, "\n";
aus.qwertz qwertz
Gibt:$, = ':'; @a = (123, 456, 789); $aref = \@a; print @{$aref}, "\n"; print @$aref, "\n";
aus.123:456:789 123:456:789
zugegriffen.${$aref}[1] oder $$aref[1]
Gibt$adresse{Bernd} = { Name => 'Bernd Dulfer', Str => 'Kapellenstr. 1', EMail => 'bdulfer@sybase.com', Buecher => [ 'Der Herr der Ringe', 'Per Anhalter durch die Galaxie', 'Die Farben der Magie' ] }; print 'Name: ', $adresse{Bernd}->{Name}, "\n";
aus.Name: Bernd Dulfer
Die Referenz in $adresse{Bernd} wird aufgelöst und liefert ein Hash. Aus diesem Hash wird das Element mit dem Schlüssel 'Bernd' genutzt, dessen Wert eine Referenz ist. Diese wiederum wird auch aufgelöst und liefert eine Liste, deren viertes Element einen neuen Wert zugewiesen bekommt.$adresse{Bernd}->{Buecher}->[3] = 'Goedel, Escher, Bach - Ein endl +os geflochtenes Band';
Soll etwas dereferenziertes nicht als Skalar sondern z.B. als Array genutzt werden, muß es mit Sigil und { } dereferenziert werden:
$adresse{Bernd} enthält eine Referenz auf ein anonymes Hash, auf das man mittels -> zugreifen kann.push @{$adresse{Bernd}->{Buecher}}, 'Die Eissegler von Tran-ky-ky' +;
Zur Adresse soll eine Liste von Autoren und deren Büchern zugefügt werden.
Die Autoren werden in einem Hash gespeichert. Die Schlüssel sind die Namen der Autoren, die Werte sind Referenzen auf Listen mit Buchtiteln.
Will man das Hash der Autoren separat aufbauen, ergibt sich:
Eine Referenz auf dieses Hash kann man dann zur Adresse zufügen:%autoren = ( Tolkien => [ 'Das Silmarillion', 'Nachrichten aus Mittelerde' ], Pratchett => [; 'Wachen, Wachen!', 'Tönerne Füße' ] )
Ein neues Buch von Tolkien wird mit:$adresse{Bernd}->{Autoren} = \%autoren;
an die Liste angefügt.push @{$autoren{Tolkien}}, 'Der Kleine Hobbit';
Wie kann ich mir eine komplexe Datenstruktur ansehen?
Das Modul Data::Dumper liefert eine Function Dumper. Dieser Funktion übergibt man eine Referenz, Dumper erzeugt Perlcode, der die gesamte Struktur wiedergibt:
Interessant ist hier die Zeile, in mit ['Silmarillion', 'Unfinished Tales'].#!/usr/bin/perl use strict; use warnings; use Data::Dumper; my %adresse; $adresse{Bernd} = { Name => 'Bernd Dulfer', Str => 'Kapellenstr. 1', EMail => 'bdulfer@sybase.com', Buecher => [ 'Der Herr der Ringe', 'Per Anhalter durch die Galaxie', 'Die Farben der Magie' ] }; $adresse{Bernd}->{Buecher}->[3] = 'Gödel, Escher, Bach - Ein +endlos geflochtenes Band'; push @{$adresse{Bernd}->{Buecher}}, 'Die Eissegler von Tran-ky-ky' +; $adresse{Bernd}->{Autoren}->{Tolkien} = ['Silmarillion', 'Unfinish +ed Tales']; print Dumper(\%adresse);
Eine ähnliche Anzeige erhält man auch wenn man den Tk-Debugger verwendet.$VAR1 = { 'Bernd' => { 'Autoren' => { 'Tolkien' => [ 'Silmarillion', 'Unfinished Tales +' ] }, 'Buecher' => [ 'Der Herr der Ringe', 'Per Anhalter durch die Galaxie' +, 'Die Farben der Magie', 'Gödel, Escher, Bach - Ein +endlos geflochtenes Band', 'Die Eissegler von Tran-ky-ky' ], 'EMail' => 'bdulfer@sybase.com', 'Str' => 'Kapellenstr. 1', 'Name' => 'Bernd Dulfer' } };
Wie kann ich Daten aus einer Datei in eine komplexe Datenstruktur laden?
Nehmen wir an, wir haben folgende Datei:
Folgender Code erzeugt aus den Daten den uns bekannten Hash:#Kürzel Name Str EMail Buec +her Bernd |Bernd Dulfer |Kapellenstr. 1 |bdulfer@sybase.com |(Der Her +r der Ringe|Per Anhalter ...|Die Farben der Magie) Bilbo |Bilbo Beutlin |Beutelsend | |(Das Rot +e Buch des Hobbits)
Zeile 1: Hash %adressen wird deklariert.1: my %adressen; 2: 3: open ADRESSEN, 'adressen.dat' or die "Konnte Datei adressen.dat + nicht öffnen: $!\n"; 4: while (<ADRESSEN>) { 5: next if /^#/; 6: my ($kuerzel, $name, $str, $email, $buecher) = split(/\s*\|/, + $_, 5); 7: $adressen{$kuerzel} = { 8: Name => $name, 9: Str => $str, 10: EMail => $email 11: }; 12: $buecher =~ tr/()//d; 13: push @{$adressen{$kuerzel}->{Buecher}}, split /\|/, $buecher; 14: } 15: close ADRESSEN;
Dies ist nur ein Beispiel, diverse Dinge wurden hier nicht berücksichtigt, z.B. könnte ein Buchtitel Klammern enthalten usw.
Wie kann ich durch Arrays und Hashes in Datenstrukturen iterieren?
Alle Bücher einer Adresse:
Alle Autoren mit deren Büchern:foreach (@{$adresse{Bernd}->{Buecher}}) { print $_, "\n"; }
foreach (keys %{$adresse{Bernd}->{Autoren}}) { print $_, "\n"; foreach (@{$adresse{Bernd}->{Autoren}->{$_}}) { print "\t", $_, "\n"; } }
Wofür braucht man Referenzen auf Subroutines?
Referenzen auf Subroutines braucht man für verschiedene Dinge:
Callbacks:
In einem Modul soll eine Subroutine des Programmes ausgeführt werden, ohne daß das Modul weiß, wie die Subroutine heißt.
Dem Modul wird eine Referenz auf die Subroutine übergeben. So kann diese ausgeführt werden:
Tk Programmierer kennen die Verwendung von Callbacks besonders gut, da Events (Mouse Click, Button, ...) an Callbacks übergeben werden.Package Mod; my $callback; sub set_callback { $callback = shift; } sub do_something { do_this(); do_that(); &$callback; do_something_else(); } . . . 1; __END__ #!/usr/bin/perl use strict; use warnings; use Mod; Mod::set_callback(\&print_rubbish); Mod::do_something(); sub print_rubbish ( print "Rubbish!\n"; }
Dispatch Listen:
Um größere if/elsif/else Konstruktionen zu vermeiden, werden die Code Stücke in Subroutines gepackt.
Referenzen auf die Subroutines werden in einem Hash gespeichert, dessen Keys den Bedingungen entsprechen.
%dispatch = ( insert => \&insert, update => \&update, delete => \&delete ) $dispatch{$token}->($query);
Update: changed <pre> to <code>
Update: Falsche Klammern an zwei Stellen, gefunden von petral
Update: diverse Tippfehler
Update: Link zu (PEGS) ersetzt
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: (lang: de) Referenzen
by Rudif (Hermit) on Nov 27, 2001 at 04:36 UTC | |
Re: (lang: de) Referenzen
by Sergej (Initiate) on Jul 27, 2006 at 21:03 UTC | |
Re: (lang: de) Referenzen
by Spenser (Friar) on Dec 14, 2001 at 05:47 UTC |