|
|
 |

|

 |

| Community » Perl: Allgemeines Forum |
|
Frage zu Referenzen
|
Seitenanfang |
| Hallo! Ich habe folgende Frage: Ich habe eine Subroutine habe, die Daten aus einer Datei liest und diese dann in einem Hash zurückgibt:
sub readfile { my %readfile; open(FILE,"<@_[0]"); while (<FILE>) { /^(.+)\t(.*)\t/; $readfile{$1}=$2; } close(FILE); return %readfile; }
Bisher lese ich den Hash so aus:
my %readhash = &readfile("pfad/zur/datei.db"); Ich kann dann mit $readhash{'name'} auf die Daten des Schlüssels 'name' zugreifen.Da hier ja immer der komplette Hash in %readhash zurückkopiert wird will ich das nun aus Preformancegründen mit einer Referenz lösen. my $readhash = \&readfile("pfad/zur/datei.db");Und dann dereferenzieren:
my $name = $$readhash{'name'};
Nun die Frage: Funktioniert das so überhaupt UND wird eigendlich jedes mal, wenn ich einer Variable einen Hashref-Wert (zB $$readhash{'name'}) zuweise die Subroutine aufgerufen und die Datei neu gelesen? zB:
my $name = $$readhash{'name'}; my $strasse = $$readhash{'strasse'}; my $plz = $$readhash{'plz'}; my $ort = $$readhash{'ort'};
Wird da die Datei nun einmal oder viermal gelesen? Wäre wirklich wichtig, denn diese Datei wird sehr oft gelesen. mfg, Perler
Datum: 20.03.2007-22:37

|
re: Frage zu Referenzen
|
Seitenanfang |
my $readhash = \&readfile("pfad/zur/datei.db");
Hier erhälst du keine Referenz auf deinen Hash, denn Subroutinen geben eine sogenannte "flache Liste" zurueck. Aus deinen Hash wird also eine Liste, die Informationen dass es zuvor ein Hash war geht dabei verloren, am Ende ist es immer eine Liste. An einen weiteren Beispiel wird das noch einmal verdeutlicht sub foo { # ... return(%hash, @array); } my @retval = foo();
%hash und @array werden zu einer einzigen Liste, das heiszt wo in @retval jetzt die Werte des Hashes enden und die des Arrays beginnen laesst sich nicht feststellen. Um die Identitaet von Hash und Array beibehalten zu koennen musst du schon beim return Referenzen zurueckgeben. sub foo { # ... return(\%hash, \@array); } my @retval = foo(); printf("RefType: %s\n", ref($_)) for @retval; #ERGEBIS: # #| RefType: HASH #| RefType: ARRAY #
Bei deinen Codestueck passiert noch etwas besonderes das man so nicht erwartet. my $readhash = \&readfile("pfad/zur/datei.db");
Erklaere ich aber nochmal an meinen Beispiel sub foo { return('A' .. 'E'); }
Wie oben erklaert wird eine Liste zurueckgegeben. Setzt du nun vor den Aufruf der Subroutine einen Backslash zum Referenzieren, dann wird statt der Liste eine Liste von Referenzen dieser Werte zurueckgegeben. my @liste = \($foo, %bar, @baz);
ist das selbe wie my @liste = (\$foo, \%bar, \@baz);
Im skalaren Kontext, so wie das bei deinen Funktionsaufruf der Fall ist, erhaelst du nicht die gesamte Liste der Referenzen sondern nur die letzte Referenz. my $ref = \($foo, %bar, @baz);
In diesen Fall enthaelt $ref nur eine Referenz auf @baz. Wenn du dir von deiner Subroutine eine Referenz auf einen Hash zurueckgeben laesst dann wird der Code der Sub _nicht_ jedesmal ausgefuehrt wenn du auf die Referenz zugreifst. Es gibt aber auch Referenzen auf Subroutinen, wenn man dann dereferenziert wird die Subroutine ausgefuehrt. sub foo { # ... } my $subRef = \&foo; &$subRef("bar"); # oder ... $subRef->("bar");
Und im folgenden Code siehst du deinen Subroutinenaufruf und die Referenzierung einer Subroutine noch einmal im Vergleich. my $readhash = \&readfile("pfad/zur/datei.db"); my $subRef = \&foo;
Der Unterschied sollte klar sein, im zweiten Aufruf fehlt die Argumentliste ("pfad/zur/datei.db") deshalb wird die Subroutine nicht ausgefuehrt sondern eine Referenz darauf zurueckgeben. -- 3a2d275a5c68d91e376c562e86419f35
Datum: 21.03.2007-03:07

|
re: Frage zu Referenzen
|
Seitenanfang |
| Hallo! Danke für die ausführliche Antwort. So wie ich das sehe wäre es dann ohnehin besser so zu arbeiten:
sub readfile { my %readfile; open(FILE,"<@_[0]"); while (<FILE>) { /^(.+)\t(.*)\t/; $readfile{$1}=$2; } close(FILE); return %readfile; }my %file = &readfile("pfad/zur/datei.db");
Hier wird ja die Subroutine nur einmal aufgerufen (Datei nur einmal gelesen) und der return-Hash in %file kopiert. Der Lebensraum von %readfile endet ja mit dem Verlassen der Subroutine und dessen Inhalt sollte dann ja aus dem Arbeitsspeicher gelöscht werden. Wäre das der bessere Weg oder gibts vielleicht noch eine Möglichkeit die ich nicht sehe um schneller an den Hash zu kommen? Wie gesagt, die Subroutine wird sehr oft aufgerufen und ich möchte die Belastung am Server möglichst klein halten ;-) mfg, Perler
Datum: 21.03.2007-08:32

|
re: Frage zu Referenzen
|
Seitenanfang |
| du kannst auch deiner funktion eine referenz auf ein hash mitgeben... sub readfile($) { my $file = shift; my $hashref = shift; open my $fh, '<', $file or die $!; while (<$fh>) { /^(.+)\t(.*)\t/; $hashref->{$1} = $2; } close($fh); } my %file; readfile("pfad/zur/datei.db", \%file); print qq($file{$_}\n) for (keys %file);
Datum: 21.03.2007-09:57

|
re: Frage zu Referenzen
|
Seitenanfang |
| Hehe, da hät ich auch selbst drauf kommen können. Der Subroutine einfach sagen, wohin sie die Daten schreiben soll *gg* Das ist auf jeden Fall besser als den Hash zurückzukopieren. Eine Frage: Warum verwendest du für den Filehandle eine Variable und warum wird die Subroutine mit einem $ als Argument eingeleitet (sub readfile($))?? mfg, Perler
Datum: 21.03.2007-10:20

|
|

|

|

|
 |

|

|
|