| perlreftut Dokumentation | Download als POD | Wie kann ich hier etwas ändern? |
Chicago, USA
Frankfurt, Deutschland
Berlin, Deutschland
Washington, USA
Helsinki, Finnland
New York, USA
und Sie wollen eine Ausgabe erzeugen, das Land einmal genannt und danach eine alphabetische Liste der Städte aus diesem Land:
Finnland: Helsinki.
Deutschland: Berlin, Frankfurt.
USA: Chicago, New York, Washington.
Der natürliche Weg dieses Ziel zu erreichen ist es, einen Hash zu benutzen, dessen Schlüssel die Ländernamen sind. Verbunden mit jedem Ländernamen ist eine Liste der Städte in diesem Land. Teile jede eingelesene Zeile in "Stadt" und "Land", schaue in der Liste der Städte, die in dem Land sind, nach und hänge die Stadt ans Ende der Liste. Wenn die Datei fertig eingelesen wurde, iteriere wie üblich über den Hash und sortiere jede Städteliste bevor Du diese ausgibst.
Wenn Hash-Werte keine Listen sein dürfen, haben Sie verloren. In Perl4 dürfen Hash-Werte keine Listen sein; es dürfen nur Strings sein. Sie haben verloren. Sie müssen vielleicht alle Städte irgendwie in einem String kombinieren und wenn es an die Ausgabe geht müssen Sie den String wieder in eine Liste teilen, diese Liste sortieren und wieder als String kombinieren. Das ist chaotisch und Fehleranfällig. Und es ist frustrierend, weil Perl wirklich gute Listen kennt die das Problem lösen könnten - wenn Sie diese einsetzen könnten.
\ vor die Variable stellen, bekommen Sie eine Referenz auf diese Variable.
$aref = \@array; # $aref enthält eine Referenz auf @array
$href = \%hash; # $href enthält eine Referenz auf %hash
Wenn die Referenz in einer Variablen wie $aref oder $href gespeichert ist, können Sie diese genauso kopieren und speichern wie jeden anderen Skalaren Wert:
$xy = $aref; # $xy enthält jetzt eine Referenz auf @array
$p[3] = $href; # $p[3] enthält jetzt eine Referenz auf %hash
$z = $p[3]; # $z enthält jetzt eine Referenz auf %hash
Diese Beispiele zeigen, wie Referenzen auf Variablen mit Namen erzeugt werden. Manchmal möchten Sie ein ein anonymes Array oder einen anonymen Hash erzeugen. Dies ist analog zu der Möglichkeit, den String "\n" oder die Zahl 80 zu benutzen ohne diese in einer benannten Variablen zu speichern.
Erzeugung Regel 2
[ ITEMS ] erzeugt ein neues, anonymes Array und gibt eine Referenz auf dieses Array zurück. { ITEMS } erzeugt einen neuen, anonymen Hash und liefert eine Referenz auf diesen Hash.
$aref = [ 1, "foo", undef, 13 ];
# $aref enthält jetzt eine Referenz auf ein Array
$href = { APR => 4, AUG => 8 };
# $href enthält jetzt eine Referenz auf einen Hash
Die Referenzen, wie sie in Regel 2 erzeugt werden sind identisch mit den Referenzen wie sie in Regel 1 erzeugt werden.
# Dieses:
$aref = [ 1, 2, 3 ];
# macht das gleiche wie:
@array = (1, 2, 3);
$aref = \@array;
Die erste Zeile ist eine abkürzende Schreibweise der folgenden zwei Zeilen, mit der Ausnahme dass es keine überflüssige Array-Variable @array erzeugt.
$aref eine Referenz auf ein Array enthält, können Sie {$arref} überall dort verwenden wo Sie normalerweise den Namen eines Arrays verwenden würden. Zum Beispiel @{$aref} an Stelle von @array .
Hier einige Beispiele:
Arrays:
@a @{$aref} Ein Array
reverse @a reverse @{$aref} "dreht das Array um"
$a[3] ${$aref}[3] Ein Element des Arrays
$a[3] = 17; ${$aref}[3] = 17 Zuweisung zu einem Element
In jeder Zeile stehen zwei Ausdrücke, die das gleiche machen. Die linke Version arbeitet mit dem Array @a , die rechte Version arbeitet mit dem Array, das von $aref referenziert wird, aber wenn sie das Array finden mit dem sie arbeiten, machen beide Versionen das Gleiche mit dem Array.
Eine Hashreferenz zu benutzen ist exakt das gleiche:
%h %{$href} Ein Hash
keys %h keys %{$href} Hole die Keys des Hashs
$h{'red'} ${$href}{'red'} Ein Element des Hashs
$h{'red'} = 17 ${$href}{'red'} = 17 Zuweisung zu einem Element
Verwendung Regel 2
${$aref}[3] ist schwer zu lesen, also können Sie auch $aref->[3] stattdessen schreiben.
${$href}{red} ist schwer zu lesen, also können Sie auch $href->{red} stattdessen schreiben.
In den meisten Fällen wollen Sie bei einem Array oder einem Hash ein einzelnes Element zuweisen oder auslesen. ${$aref}[3] und ${$href}{'red} haben zuviel Interpunktion and Perl lässt Sie abkürzen.
Wenn $aref eine Referenz auf ein Array enthält, dann ist $aref->[3] das vierte Element des Arrays. Verwechseln Sie das nicht mit $aref[3] , das das vierte Element eines komplett anderen Arrays ist, ein Array, das trügerisch @aref heißt. $aref und @aref haben genausowenig etwas miteinander zu tun wie $item und @item .
Genauso ist $href->{'red'} ein Teil des Hash, das von der Skalaren Variable $href referenziert wird, vielleicht sogar von einer anonymen Variablen. $href{'red'} ist Teile eines trügerisch %href genannten Hashs. Es ist leicht, das -> zu vergessen und wenn Sie das tun, bekommen Sie groteske Ergebnisse wenn Ihr Programm Array- und Hash-Elemente aus einem völlig unerwarteten Hash und Array bekommen, die Sie gar nicht verwenden wollten.
[1,2,3] ein anonymes Array erzeugt, das (1, 2, 3) enthält und eine Referenz auf das Array liefert.
Jetzt denken sie mal über
@a = ( [1, 2, 3],
[4, 5, 6],
[7, 8, 9]
);
nach
@a ist ein Array mit drei Elementen und jedes Element ist eine Referenz auf ein weiteres Array.
$a[1] ist eine dieser Referenzen. Es verweist auf ein Array, dieses Array enthält (4, 5, 6) und weil es eine Referenz auf ein Array ist, können wir nach Verwendung Regel 2 $a[1]->[2] schreiben um das dritte Element dieses Arrays zu bekommen. $a[1]->[2] ist die 6. Ähnlich dazu ist $a[0]->[1] die 2. Was wir hier haben sieht wie ein zweidimensionales Array aus. Sie können $a[ZEILE]->[SPALTE] schreiben um ein Element in irgendeiner Zeile und in irgendeiner Spalte des Arrays zu lesen oder zuzuweisen.
Diese Schreibeweise sieht noch sehr umständlich aus, also gibt es eine weitere Abkürzung:
$a[1]->[2] können wir $a[1][2] schreiben; das bedeutet das Gleiche. Anstelle von $a[0]->[1] können wir $a[0][1] schreiben; es bedeutet das Gleiche.
Jetzt sieht es wie ein zweidimensionales Array aus!
Sie können sehen, warum der Pfeil wichtig ist. Ohne ihn müssten wir ${$a[1]}[2] anstatt $a[1][2] schreiben. In dreidimensionalen Array können wir $x[2][3][5] anstatt dem unlesbaren ${${$x[2]}[3]}[5] schreiben.
1 while (<>) {
2 chomp;
3 my ($city, $country) = split /, /;
4 push @{$table{$country}}, $city;
5 }
6
7 foreach $country (sort keys %table) {
8 print "$country: ";
9 my @cities = @{$table{$country}};
10 print join ', ', sort @cities;
11 print ".\n";
12 }
Das Programmm besteht aus zwei Teilen: Zeilen 1-5 lesen die Eingabe und erzeugen eine Datenstruktur und Zeilen 7-12 analysieren die Daten und geben den Report aus.
Im ersten Teil ist die Zeile 4 die wichtige Zeile. Wir benötigen einen Hash, %table , desen Schlüssel die Ländernamen sind und die Werte sind (Referenzen auf) Arrays mit den Städtenamen. Nach dem Erhalten von Stadt- und Ländernamen schaut das Programm nach $table{$country} , was (eine Referenz auf) eine Liste auf die Städte enthält, die bisher für das Land gefunden wurden. Die Zeile 4 ist analog zu
push @array, $city;
mit der Ausnahme, dass der Name array durch die Referenz {$table{$country}} ersetzt wurde. Das push fügt den Städtenamen an das Ende des referenzierten Arrays hinzu.
Im zweiten Teil ist die Zeile 9 die wichtige Zeile. Hier ist wieder $table{$country}} (eine Referenz auf) eine Liste von Städten in dem Land, so dass wir die Originalliste wieder herstellen und diese in das Array @cities , durch @{$table{$country}} kopieren können. Die Zeile 9 ist analog zu
@cities = @array;
mit der Ausnahme, dass array durch die Referenz {$table{$country}} ersetzt wurde. Das @ teilt Perl mit, dass das gesamte Array zu nehmen ist.
Der Rest des Programms ist nur die bekannte Verwendung von chomp , split , sort , print , und hat nichts mit Referenzen zu tun.
Es gibt eine Kleinigkeit, die ich ausgelassen habe. Angenommen, das Programm hat gerade die erste Zeile der Eingabe eingelesen in der Griechenland vorkommt. Wir sind in Zeile 4, $country ist 'Griechenland' und $city ist 'Athen' . Das ist die erste Stadt in Griechenland, $table{$country} ist undefined - weil es noch keinen Schlüssel 'Griechenland' in %table gibt. Was macht hier die Zeile 4?
4 push @{$table{$country}}, $city;
Das ist Perl, also macht es das Richtige. Es bemerkt, dass Sie Athen in ein Array einfügen wollen, das nicht existiert. Also ist es hilfreich, ein neues, leeres, anonymes Array für Sie zu erzeugen, in der Tabelle anlegen und dann Athen dort einfügen. Das wird `autovivification' genannt.
Sie können auf alles referenzieren, sogar auf Skalare, Funktionen und andere Referenzen.
Bei Verwendung Regel 1 können Sie die geschweiften Klammern immer dann weglassen, wenn der Teil innerhalb der Klammern eine atomare Skalare Variable wie $aref ist. Zum Beispiel @$aref ist das gleiche wie @{$aref} und $$aref[1] ist das gleiche wie ${$aref}[1] . Wenn Sie gerade beginnen, sollten Sie sich Gewohnheit aneignen, immer die geschweiften Klammern zu benutzen.
Zum Überprüfen, ob eine Variable eine Referenz enthält, benutzen Sie die `ref'-Funktion. Diese gibt true zurück wenn der Parameter eine Referenz ist. Das ist ein bißchen besser als: Es gibt HASH für ein Hashreferenz und ARRAY für eine Arrayreferenz zurück.
Wenn Sie eine Referenz als String benutzen bekommen Sie solche Strings wie
ARRAY(0x80f5dec) oder HASH(0x826afc0)
Wenn Sie jemals solch einen String wie diesen sehen, werden Sie erkennen, dass Sie fälschlicherweise eine Referenz ausgegeben haben.
Ein Seiteneffekt dieser Darstellung ist, dass Sie eq benutzen können, um zu sehen ob zwei Referenzen auf das gleiche Ziel zeigen. (Aber Sie sollten immer stattdessen == benutzen weil es viel schneller ist.)
Sie können einen String so benutzen als wäre es eine Referenz. Wenn Sie den String "foo" als eine Arrayreferenz benutzen wird es als Referenz auf das Array @foo betrachtet. Dies wird soft reference oder symbolic reference genannt.
mjd-perl-ref+@plover.com )
Dieser Artikel erschien usprünglich im The Perl Journal ( http://www.tpj.com/ ) volume 3, #2. Mit Erlaubnis nachgedruckt
Der Originaltitel war Understand References Today .
| I | Attachment | Action | Size | Date | Who | Comment |
|---|---|---|---|---|---|---|
| |
perlreftut.pod | manage | 16.4 K | 2005-05-20 - 15:02 | ReneeBaecker |