Thread Rückgabe mehrerer Hashes geht nicht (22 answers)
Opened by SchaubFD at 2008-02-13 09:24

KurtZ
 2008-02-13 22:09
#105855 #105855
User since
2007-12-13
411 Artikel
BenutzerIn
[default_avatar]
SchaubFD+2008-02-13 13:40:07--
Das ist dann aber eine Lösung die nur über Referenzen läuft, nicht über einen Hash oder ? Ich frage mich immer noch, warum muss man diese unterschiedlichen Typen nutzen, um auf einen Hash zugreifen zu können?


Deine Frage ist berechtigt, und da muss man weiter ausholen. es betrifft nicht nur Parameterübergaben sondern hängt mit der Besonderheit von Perl bezüglich verschachtelten Strukturen zusammen, die nur mit Referenzen möglich sind.

Generell gilt, dass man Listen von Skalaren Elementweise aufeinander abbilden kann.
Code (perl): (dl )
( $a, $b, $c ) = ( 1, 2, 3 ) ;# => $a=1, $b=2 usw.

trägt man aber rechtsseitig ein Array oder Hash ein, wird es alles zu einer eindimensionalen Liste abgeflacht (Flattening), also:

Code (perl): (dl )
1
2
3
4
5
6
7
@x = ( x1, x2, x3 ); 
%y=( y1 => "Y1 );

( $a, $b, $c ) = ( %y, $x, 1, 2, 3 );   

#                   = ( y1, Y1, x1, x2, x3, 1, 2, 3) 
#                   => $a == "y1",  $b == "Y1",  $c == "x1"  


Linksseitig wirkt der erste eingetragenen Array oder Hash wie ein Staubsauger, der alle folgenden Skalare aufnimmt

Code (perl): (dl )
1
2
3
($a,$b,@X,$c) =  (%y,$x,1,2,3);   
#              => @X = (x1,x2,x3,1,2,3) , $a = "y1",   $b = "Y1", 
#              => insbesondere $c = undef  


wenn du also schreibst:
Code (perl): (dl )
( @X ) = ( @x )


dann klappt deine Zuweisung, die Inhalte von @x werden 1zu1 auf @X umkopiert

Hingegen
Code (perl): (dl )
( @X , @Y ) = ( @x , @y ) 


liefert aber nur @X == ( @x , @y ) und @Y == ()

Referenzen hingegen werden wie Skalare behandelt, d.h. kein Aufsaugen!
Code (perl): (dl )
( $X_ref , $Y_ref ) = ( \@x , \@y ) 

Es funktioniert und hat den entscheidenden Unterschied dass hier keine einzelnen Arrayelemente umkopiert werden, sondern dass es sich auf beiden Seiten um die gleiche Referenz des selben Arrays handelt.

also
Code (perl): (dl )
1
2
3
$X_ref->[0] = "X" ;
# gilt genau dann wenn  
$x[0] = "X"  


Das ist ein entscheidender Vorteil, wenn man die übergebenen Arrays/Hashs direkt manipulieren will, aber auch das eventuell große Datenmengen nicht unnötig herumumkopiert werden müssen.

Was dich (wie auch mich) wohl nervt ist das du fortan immer den Pfeil mitschreiben musst um zu dereferenzieren.

Je nachdem ob du auf ein Alias oder eine Kopie zugreifen willst kannst du auch wieder derefrenzieren

Code (perl): (dl )
1
2
@X = @$X_ref   ; kopiert die Werte nach @X um
*X = $X_ref         ; legt ein Alias an, also  \@X==\$X_ref   


das letzte Konstrukt ist ein Typglob und ist mit Vorsicht zu genießen, weil es nur mit Packagevariablen funktioniert, dafür aber recht stringent, du kannst nämlich schreiben

Code (perl): (dl )
( *X , *Y , $A )=( \@x , \@y , $a)  


Weil du damit aber keine lexikalischen (my) Variablen aliasen kannst wird dir das aber heutzutage kaum jmd empfehlen.... dafür gibts in Perl5 leider keinen eingebauten Mechanismus, einziger Ausweg wäre da, das Modul CPAN:Data::Alias dafür zusätzlich zu nutzen.

Als die moderneren my-Variablen eingeführt wurden, wurde leider versäumt deren Aliasing direkt mit einzubauen.

Bedenke bitte das es in anderen Sprachen auch nur Referenzen übergeben werden, allerdings implizit!

In Javascript z.B. eine Referenz auf ein Array-Objekt. Umkopieren oder Flattening musst du da auch (mit Ausnahmen) explizit fordern. In Perl ist es halt defaultmäßig eingebaut, und muss daher im Bedarfsfall explizit verhindert werden.

Das hat Vor- und Nachteile, Perl erlaubt z.B. Konstrukte wie

Code (perl): (dl )
( $a , $b , $c , @X ) = ( @X ) 
d.h das Array @X wird um die ersten 3 Elemente gekürzt und diese auf $a-$c kopiert.

oder

Code (perl): (dl )
%A = ( %A, %B, %C )  
d.h. die Hashes werden zusammen auf %A kopiert!
Dabei werden mehrfach vorkommende Keys überschrieben werden.
(%B dominiert %A, %C dominiert alle anderen, usw)

SchaubFD+2008-02-13 13:40:07--
Auch wenn meine Fragen nervig sind, sind Übergaben von Hashes nur über Referenzen möglich?


Ein einzelnes Hash kannst du wie oben gezeigt per Einzelwerte umkopieren.

Bei mehreren kommst du an Referenzen nicht vorbei, ein zusätzlicher Backslash wird dich auch kaum umbringen.

AFAIK gilt übrigens auch
Code (perl): (dl )
\( %a , %b ) == (  \%a , \%b ) 

womit du noch mehr Backslashes einsparen könntest, wenn nur Referenzen übergeben werden.
TMTOWTDYOG (there's more than one way to dig your own grave)

View full thread Rückgabe mehrerer Hashes geht nicht