perlunity.de - PERL | JAVASCRIPT | PHP | MySQL | APACHE



#!/COMMUNITY

Members: 5597
davon online: 1
weitere User: 1
Click for quality!



22.01.2018 / 15:10

Community-Member werden   |   Paßwort vergessen   |   OnlineMonitor (1) Wer ist online ... OnlineMonitor starten !
     

 

Home


PERLscripts


PHPscripts


JAVAscripts


Hilfreiches


Links2www


Newscenter


Community


Interna




'Type Globs' und Referenzen

Typeglobs sind Einträge in die Symboltabelle. (Diese ist im Hash %:: abgespeichert.) In Perl kann man alle Objekte mit einem bestimmten Namen referenzieren, indem man diesen Namen mit dem Präfix * versieht: *foo. Das nennt man dann type globbing, weil der Stern als Wildcard für alle anderen Präfix-Buchstaben wie $, %, & stehen kann. Folgendes Beispiel soll diesen Sachverhalt erhellen:

$foo = 100;
@foo = ('aa','bb','cc');
sub foo {
    print "I am foo\n";
}

sub deref {
    local(*bar) = @_;
    print $bar[0],"\n";
    print $bar,"\n";
    &bar;
}
print "Ref: ",*foo,"\n";
&deref(*foo);

Die Ausgabe dieses Programmes sieht wie folgt aus:

Ref: *main'foo
aa
100
I am foo

In Perl 4 wurde dieser Mechanismus verwendet, um die Uebergabe von Referenzen an Subroutinen zu simulieren. In Perl 5 werden dafür echte Referenzen verwendet (siehe unten). Natürlich funktioniert der alte Mechanismus auch in modernen Versionen.


Referenzen

Mir dem type globbing erhält man symbolische Referenzen, dh. sie beinhalten den Namen einer Variablen, vergleichbar mit einem symbolischen Link in einem Unix-Filesystem. In Perl 5 gibt es auch sogenannte harte Referenzen. Sie zeigen direkt auf das der Variabeln zugrundeliegende Objekt, welches eine skalare Variable, ein Array oder ein assoziativer Array (Hash) sein kann, aber auch eine Subroutine oder ein Filehandle. Diese Referenzen sind 'intelligent'. Sie führen Buch über die Anzahl Referenzen auf ein Objekt und geben das Objekt frei, sobald diese Anzahl auf Null geht.
Eine Variable wird von Perl nie implizit dereferenziert. Falls eine skalare Variable eine Referenz ist, wird sie sich immer als skalare Variable verhalten und nicht als der Typ, den sie referenziert. Diese Tatsache hat syntaktische Konsequenzen (siehe perldsc- , resp. perlLoL- Manpage).

Erzeugen von Referenzen

  1. Mit dem Backslash-Operator:
  2. $scalarref = \$foo;
    $arrayref  = \@ARGV;
    $hashref   = \%ENV;
    $coderef   = \&handler;
    $globref   = \*STDOUT;
  3. Als Referenz zu einem anonymen Array, Hash oder Funktion:
  4. $arrayref = [1, 2, ['a', 'b', 'c']];
    
    $hashref = {'Adam' => 'Eve', 'Clyde' => 'Bonnie');
    
    $coderef = sub { print "Boink!" };
  5. Referenzen werden häufig durch spezielle Subroutinen, den Konstruktoren zurückgegeben:
  6. $objref = new Doggie (Tail => 'short', Ears => 'long');
    $objref->bark();     # Aufruf einer Methode
  7. Referenzen zu Filehandles werden durch Referenzen zu einem Typeglob erzeugt. Folgendes Beispiel zeigt, wie ein Filehandle als Parameter einer Subroutine übergeben wird:
  8. splutter(\*STDOUT);  #  Aufruf
    sub splutter {       #  Deklaration
        my $fh = shift;
        print $fh "gugus\n";
    }

Dereferenzieren

  1. Ueberall, wo man einen Identifier als Teil eines Variablen- oder Subroutinennamens schreiben würde, kann dieser Identifier durch eine einfache skalare Variable, welche eine Referenz auf den gewünschten Typ darstellt, ersetzt werden.
  2. $bar = $$scalarref;
    push(@$arrayref, $filename);
    $$arrayref[0] = "Januar";
    $$hashref{"KEY"} = "VALUE";
    &$coderef(1,2,3);
    print $globref "output\n";
  3. Ueberall, wo man einen Identifier als Teil eines Variablen- oder Subroutinennamens schreiben würde, kann dieser Identifier durch einen BLOCK, welcher eine Referenz auf den gewünschten Typ zurückgibt, ersetzt werden.
  4. $bar = ${$scalarref};
    push(@{$arrayref}, $filename);
    ${$arrayref}[0] = "Januar";
    ${$hashref}{"KEY"} = "VALUE";
    &{$coderef}(1,2,3);

    In diesen Fällen ist es natürlich überflüssig die geschweiften Klammern zu verwenden. Aber da ein Block einen beliebigen Ausdruck beinhalten kann, gibt es vernünftigere Beispiele:

    &{ $dispatch{$index} }(1,2,3);   # Aufruf der korrekten Subroutine
  5. Als syntaktische Variante geht auch:
  6. $arrayref->[0] = "Januar";
    $hashref->{"KEY"} = "VALUE";

    Die linke Seite vom Pfeil kann irgendein Ausdruck sein, welcher eine Referenz zurückgibt.

    $array[$x]->{"foo"}->[0] = "Januar";

    Vor dieser Anweisung könnte $array[$x] undefiniert sein, wird aber an dieser Stelle automatisch zu einer Referenz auf einen Hash. Dasselbe gilt analog für $array[$x]->{"foo"}. Die Pfeile zwischen den Klammern müssen nicht geschrieben werden:

    $array[$x]{"foo"}[0] = "Januar";
  7. Eine Referenz kann aber auch eine Referenz auf ein Objekt (zu einer Klasse) sein. Dann gibt es vermutlich Methoden, welche durch diese Referenz zugegriffen werden können:
  8. $obj->methode($param);

    Wir werden im nächsten Kapitel mehr davon hören. Und dann gibt es noch die perlobj-Manpage.


Mit den Referenzen von Perl 5 ist es einfach mehrdimensionale Datenstrukturen (Arrays von Arrays, Arrays von Hashes, Hashes von Subroutinen etc. zu erzeugen (siehe perldsc- resp. perlLoL-Manpage).
Weitere Angaben über Referenzen findet man in den perlref -Manpage.

Referenzen als Parameter von Subroutinen

Manchmal möchte man nicht einen Array als Wertparameter übergeben, sondern innerhalb der Subroutine mit der globalen Variablen arbeiten (PASCAL: VAR-Parameter). Natürlich ist es schneller eine Referenz zu übergeben, anstelle eines ganzen Arrays, daneben ist es die einzige Möglichkeit, mehrere Arrays als Parameter zu übergeben. (Warum?)
Das folgende Beispiel gibt die letzten Elemente von einer Liste von Arrays aus:

@letzte = popmany( \@a, \@b, \@c, \@d );
sub popmany {
    my $aref;
    my @retlist = ();
    foreach $aref (@_) {
        push @retlist, pop @$aref;
    }
    return @retlist;
}

Das ist ja alles sehr schön, aber wie bekomme ich mehrere Arrays oder Hashes als Rückgabewerte? Wie wär's mit folgendem:

($aref, $bref) = func(\@a, \@b);
print "@$aref has more then @$bref\n";
sub func {
    my ($cref, $dref) = @_;
    if (@$cref > @$dref) {
        return ($cref, $dref);
    } else {
        return ($dref, $cref);
    }
}



Uebung

Man nehme die Uebung des letzten Kapitels und tausche die Parameter der Subroutine aus. Damit das funktioniert, muss man eine Referenz auf den Array der Textstücke übergeben und in der Subroutine den Array dereferenzieren.



zurück Inhalt weiter






-
-