QuoteHallo!
Ich habe bisher PERL nur für kleinere Aufgaben und Skripte verwendet, wollte jetzt aber mal etwas tiefer einsteigen.
Gut, erste Lektion. Es heißt "Perl" nicht "PERL". ;)
GwenDragon zeigt ein gutes Beispiel, aber irgendwie fehlt die Erklärung...
Daher hier nochmal eine kleine Erklärung von mir. Stell dir vor du möchtest eine Funktion schreiben die zwei Arrays übergeben bekommt und testet ob beide Arrays identisch sind. Hier in den Beispiel zeige ich erstmal nur was übergeben wird.
Du könntest letztendlich sowas versuchen.
my @a1 = qw( a b c );
my @a2 = qw( a b c );
is_array_equal(@a1, @a2);
sub is_array_equal {
my (@a1, @a2) = @_;
print "a: @_\n";
print "a1: @a1\n";
print "a2: @a2\n";
}
Das ganze klappt aber aus mehreren Gründen nicht mehr. Als erstes kommt der Funktionaufruf.
Wie du hoffenltich bisher weißt werden hier nicht zwei Argumente übergeben also zwei Arrays. Sondern die Arrays werden "flattened" und in einer liste umgewandelt und dann so der Subroutine übergeben.
Das siehst du dann auch in der Ausgabe der Subroutine. Alle Argumente sind in "@_" enthalten.
Dieses würde natürlich auch nicht funktionieren. Da das erste @1 immer alles aus @_ enthalten würde und nichts mehr übrig lassen würde.
Um es also kurz zu sagen. Innerhlab der Subroutine hast du keine Information mehr welche Elemente zu Array1 gehörten oder welche Elemente zu Array2 gehörten.
Damit das ganze dann doch Funktioniert musst du nicht das Array an sich der Funktion übergeben, sondern du musst sozusagen eine Skalare Variable übergeben die auf dein Array zeigt. Und genau das ist es was eine Referenz macht. Um den oberen Code nochmals abzuändern.
my @a1 = qw( a b c );
my @a2 = qw( a b c );
is_array_equal(\@a1, \@a2);
sub is_array_equal {
my ($a1, $a2) = @_;
print "a: @_\n";
print "a1: $a1\n";
print "a2: $a2\n";
}
Du übergibst nun deiner Funktion zwei Skalare Werte und jeder Skalar zeigt wiederrum auf einem Array. Dadurch bleibt nun die Information enthalten. Du kannst die Referenzen dereferenzieren um auf die Inhalte des Arrays zuzugreifen. Du solltest bisher dann wohl schon Wissen wie das geht daher erspare ih mich hier eine Erklärung.
Ein nächster Punkt ist das du bei Referenzen sozusagen nur die "Speicherstelle" zu dem Array übergibst. Veränderst du direkt Inhalte in deiner Funktion wird das Original Array bearbeitet. Dieser Punkt ist bei der Objekt Orientierung sehr wichtig wozu du hoffentlich später auch noch kommen wirst. Um ein Beispiel zu zeigen:
my @a1 = qw( a b c );
change_array( \@a1 );
print "@a1\n";
sub change_array {
my ($a1) = @_;
$a1->[0] = "f";
}
Die Ausgabe des Programmes ist nun:
Da $a1 innerhalb der Subroutine auf das äußere Array zeigt. Und du das äußere Array direkt veränderst.
Und bevor jemand ankommt und mich versucht zu berichtigen. Ja es würde auch ohne Referenzen gehen.
my @a1 = qw( a b c );
change_array( @a1 );
print "@a1\n";
sub change_array {
$_[0] = "f";
}
Dieses würde ebenfalls korrekt "f b c" ausgeben. Da Perl by Default seine Elemente by Reference übergibt. Allerdiengs solltest du lieber das erste Beispiel nehmen. Da du dann direkt auf @_ zugreifen musst und bei mehreren Argumenten es ziemlich unleserlich wird. Und es ist flexibler. Zwei Arrays kann ich mit dieser Methode ja immer noch nicht übergeben.
Wenn dir dies noch etwas unklar ist. Meist steht am anfang ja meist soetwas wie oben. Das legt immer Kopien von den einzelnen Elementen in @_ an. Wenn eine Referenz in @_ ist dann wird zwar in diesem Fall auch eine Kopie angelegt. Aber Referenzen zeigen ja sozusagen immer nur auf irgendetwas anderes. Wenn du also eine Referenz kopierst. Zeigt auch die Kopie auf das gleiche. Durch das Derefernzieren gelangst du dann darauf worauf die Referenz zeigt.
Weitere Verwendung ist z.B. bei Tiefen Datenstrukturen. Sagen wir mal du möchtest mehrere Personen anlegen. Die Information zu einer Person legst du in einem Hash ab. Für jede Person musst du jetzt ein Hash anlegen und sagen wir mal du möchtest nun zu jeder Person den Namen ausgeben.
Du könntest also soetwas Coden:
my %ich = (
name => 'Raab',
vorname => 'David',
geburtstag => '19.02.1983',
wohnort => 'Essen',
);
my %du = (
name => 'toppsino',
vorname => 'Dirk',
geburtstag => '1.1.1970',
wohnort => 'Bad Nauheim',
);
print "$ich{name}\n";
print "$du{name}\n";
Das hat aber etliche Nachteile. Du musst nun für jede weitere Person die du anlegen möchtest ein neuen hash mit Namen ausdenken. Und wenn du die Namen alle ausgeben möchtest dann musst du für jeden Hash eine print anweisung schreiben. bzw extra bei der Ausgabe hinzufügen.
Weiterhin ist das ganze nicht mehr zur Laufzeit veränderbar. Stell dir vor du möchtest ein Programm schreiben das nun zur Laufzeit Nach den Personendaten fragt. Ohne das Wissen von Referenzen müsstest du nun irgendwie ein hash erzeugen und diesen irgendwie abspeichern und dein Programmcode so abändern das er den neuen Namen ausgiebt.
Mit dem Wissen von Referenzen ist das ganze aber deutlich einfacher. Die Personendaten speicherst du immer noch in einem Hash. Anstatt allerdiengs die Hashes direkt namen zu geben Speicherst du den Hash in einem Array ab. Das Array ist dynamisch erweiterbar und du kannst auch zur Laufzeit einfach neue Werte dem Array anhängen. Sowas nennt man dann Tiefe Datenstruktur da du nun ein Array hast was mehrere Hashes enthält. Ein Array of Hashes oder kur AoH.
Der erste schritt sieht also so aus:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
my %ich = (
name => 'Raab',
vorname => 'David',
geburtstag => '19.02.1983',
wohnort => 'Essen',
);
my %du = (
name => 'toppsino',
vorname => 'Dirk',
geburtstag => '1.1.1970',
wohnort => 'Bad Nauheim',
);
my @personen = ( \%ich, \%du );
for my $person ( @personen ) {
print $person->{name}, "\n";
}
Das was du bisher daraus gewonnen hast ist die flexibilität bei der Ausgabe. Du musst nun nicht mehr für jede Person einzelnd ein Print Statement schreiben. Sondern du gehst einfach das Arrays durch. Jeder Wert des Arrays zeigt auf einem Hash. Mit dem Derefernzieren (Pfeil) kannst du nun auf den Ursprünglichen hash zu greifen. Und dort jeweils den Key "name" ausgeben.
Ein weiterer Weg zur Flexibilität ist es nun anstatt vorher Hashes zu erzeugen und diese dann dem Array hinzuzufügen direkt Hashreferenzen zu erzeugen die im Array abgelegt werden. Um eine Arrayreferenz zu erzeugen werden geschweifte Klammern genutzt. Das solltest du eventuell schon Wissen.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
my @personen = (
{
name => 'Raab',
vorname => 'David',
geburtstag => '19.02.1983',
wohnort => 'Essen',
},
{
name => 'toppsino',
vorname => 'Dirk',
geburtstag => '1.1.1970',
wohnort => 'Bad Nauheim',
},
);
for my $person ( @personen ) {
print $person->{name}, "\n";
}
Hier hast du jetzt nur noch ein Array. Die geschweiften Klammern innerhlab des Arrays erzeugen nun eine Hashreferenz. Auch eine sogenannte Anonyme Hashreferenz da es keinen Hashnamen mehr gibt um direkt auf den Hash zuzugreifen. Du kommst nur noch an die Elemente heran wenn du durch das Array durchgehst. In diesem Fall benötigen wir aber auch keinen Namen. Ehrlich gesagt waren sie nur im weg.
Der nächste Schritt ist die Gültigkeit von Datenstrukturen zu Wissen. Eine Datenstruktur, also Array, Hash etc. lebt solange solange noch eine Referenz auf diese Datenstruktur zeigt. Solange also irgendeine Referenz auf den Speicherbereich der Variable zeigt, wird diese Variable nicht zerstört. Sowas ist der sogenannte Garbage Collector ein sogenannter "Reference Counter".
Für das obere Beispiel zeige ich dann nämlich eine weitere Verwendung. Nämlich das erzeugen eines Hashes und das zurückgeben einer Referenz auf dem Hash in der Subroutine.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
my @personen = (
{
name => 'Raab',
vorname => 'David',
geburtstag => '19.02.1983',
wohnort => 'Essen',
},
{
name => 'toppsino',
vorname => 'Dirk',
geburtstag => '1.1.1970',
wohnort => 'Bad Nauheim',
},
);
# Nach einer Person Fragen. Subroutine generiert
# aus den eingaben einen hash und gibt eine hashreferenz
# darauf zurück.
my $person = ask_person();
# Diese hashreferenz zu @personen hinzufügen
push @personen, $person;
# alle Namen ausgeben
for my $person ( @personen ) {
print $person->{name}, "\n";
}
# Subroutine die nach Personendaten fragt.
sub ask_person {
print "Bitte Name eingeben: ";
my $name = <STDIN>;
print "Bitte Vorname eingeben: ";
my $vorname = <STDIN>;
print "Bitte Geburtstag eingeben: ";
my $geburtstag = <STDIN>;
print "Bitte Wohnort eingeben: ";
my $wohnort = <STDIN>;
chomp( $name, $vorname, $geburtstag, $wohnort );
my %person = (
vorname => $vorname,
name => $name,
geburtstag => $geburtstag,
wohnort => $wohnort,
);
return \%person;
}
Nicht mehr aktiv. Bei Kontakt: ICQ: 404181669 E-Mail: perl@david-raab.de