Frage

Ich habe eine Funktion, die eine Variable und ein assoziatives Array annimmt, aber ich kann sie nicht dazu bringen, richtig zu bestehen. Ich denke, das hat etwas mit Funktionserklärungen zu tun, aber ich kann nicht herausfinden, wie sie in Perl funktionieren. Gibt es eine gute Referenz dafür und wie mache ich das, was ich brauche?

Ich sollte hinzufügen, dass es mit Referenz übergeben werden muss.

sub PrintAA
{
    my $test = shift;
    my %aa   = shift;
    print $test . "\n";
    foreach (keys %aa)
    {
        print $_ . " : " . $aa{$_} . "\n";
        $aa{$_} = $aa{$_} . "+";
    }
}
War es hilfreich?

Lösung

Übergeben Sie die Referenz anstelle des Hashs selbst. Wie in

PrintAA("abc", \%fooHash);

sub PrintAA
{
  my $test = shift;
  my $aaRef = shift;

  print $test, "\n";
  foreach (keys %{$aaRef})
  {
    print $_, " : ", $aaRef->{$_}, "\n";
  }
}

Siehe auch Perlfaq7: Wie kann ich eine {Funktion, FileHandle, Array, Hash, Methode, Regex} übergeben/zurückgeben?

Andere Tipps

Dieser Code funktioniert:

#!/bin/perl -w

use strict;

sub PrintAA
{
    my($test, %aa) = @_;
    print $test . "\n";
    foreach (keys %aa)
    {
        print $_ . " : " . $aa{$_} . "\n";
    }
}

my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \&PrintAA );

PrintAA("test", %hash);

Der entscheidende Punkt ist die Verwendung des Array -Kontexts in der my () 'Anweisung' in der Funktion.


Was macht das Array -Kontextgeschäft tatsächlich?

Klar, es lässt es richtig funktionieren.

Es bedeutet, dass der erste Wert in der @_ Array von Argumenten wird zugewiesen $test, und die verbleibenden Elemente werden dem Hash zugewiesen %aa. Angesichts der Art, wie ich es nannte, gibt es eine seltsame Anzahl von Elementen in der @_, sobald der erste Element zugewiesen ist $test, Es gibt eine gleichmäßige Anzahl von Elementen, die zugewiesen werden können %aa, Da das erste Element jedes Paares der Schlüssel ('AAA', 'BBB', 'CCC' in meinem Beispiel) ist und der zweite der entsprechende Wert ist.

Es wäre möglich zu ersetzen %aa mit @aa, In diesem Fall hätte das Array 6 Elemente darin. Es wäre auch möglich zu ersetzen %aa mit $aa, und in diesem Fall die Variable $aa würde den Wert 'AAA' und die verbleibenden Werte in enthalten @_ würde durch die Aufgabe ignoriert werden.

Wenn Sie die Klammern um die Variablenliste weglassen, weigert sich Perl, den Code zu kompilieren. Eine der alternativen Antworten zeigte die Notation:

my $test = shift;
my(%aa) = @_;

Dies entspricht so ziemlich dem, was ich geschrieben habe. Der Unterschied ist, dass nach den beiden my Aussagen, @_ Enthält nur 6 Elemente in dieser Variation, während in der Single my Version, es enthält immer noch 7 Elemente.

Es gibt definitiv andere Fragen in ALSO Über Array -Kontext.


Eigentlich habe ich nicht nach dem gefragt my($test, %aa) = @_; Ich fragte nach my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \&PrintAA ); gegen my %hash = { 'aaa' => 1, ... };

Der Unterschied besteht darin, dass die Notation {...} einen Hash -Ref erzeugt und die (...) Notation eine Liste erzeugt, die einem Hash (im Gegensatz zu Hash Ref) ordnet. In ähnlicher Weise erzeugt [...] einen Array -Ref und kein Array.

Ändern Sie in der Tat den 'Main' -Code, so dass er lautet: my (%Hash) = {...}; Und Sie erhalten einen Laufzeitfehler (aber nicht kompilieren Sie Zeit) - behandeln Sie Zeilennummern mit Vorsicht, da ich meiner Datei alternative Codierungen hinzugefügt habe:

Reference found where even-sized list expected at xx.pl line 18.
...
Use of uninitialized value in concatenation (.) or string at xx.pl line 13.

Alternative:

sub PrintAA
{
    my $test       = shift;
    my %aa         = @_;
        print $test . "\n";
        foreach (keys %aa)
        {
                print $_ . " : " . $aa{$_} . "\n";
                $aa{$_} = $aa{$_} . "+";
        }
}

Das, was Sie grundlegend fehlen, ist, dass ein assoziatives Array kein einziges Argument ist (obwohl eine assoziative Array -Referenz, wie in Paul Tomblins Antwort).

Es sieht so aus, als ob Sie in einem Verweis auf einen Hash übergeben sollten.

sub PrintAA
{
   my $test = shift;
   my $aa = shift;
   if (ref($aa) != "HASH") { die "bad arg!" }
   ....
}

PrintAA($foo, \%bar);

Der Grund, warum Sie keine machen können

my %aa = shift;

liegt daran, dass Perl alle Argumente an eine Unterroutine in eine Liste flacht, @_. Jedes Element wird kopiert, daher vermeidet das Durchgehen durch Referenz auch diese Kopien.

Wie immer gibt es verschiedene Möglichkeiten. Hier ist was Perl Best Practices, Das am meisten verehrte Stilzeiger muss über die Übergabe von Parametern an Funktionen sagen:

Verwenden Sie einen Hash benannter Argumente für jede Unterroutine mit mehr als drei Parametern

Aber da du nur zwei hast, könntest du entkommen;), wobei sie sie direkt so weitergeben:

my $scalar = 5;
my %hash = (a => 1, b => 2, c => 3);

func($scalar, %hash)

Und Funktion ist so definiert:

sub func {
    my $scalar_var = shift;
    my %hash_var = @_;

    ... Do something ...
}

Es könnte nützlicher sein, wenn Sie einen Code anzeigen könnten.

Alle oben genannten Methoden funktionieren, aber dies war immer so, wie ich es vorgezogen habe, solche Dinge zu tun:

sub PrintAA ($\%)
{
    my $test       = shift;
    my %aa         = ${shift()};
    print "$test\n";
    foreach (keys %aa)
    {
        print "$_ : $aa{$_}\n";
        $aa{$_} = "$aa{$_}+";
    }
}

Hinweis: Ich habe auch Ihren Code ein wenig geändert. Perls doppelt zitierte Saiten werden interpretieren "$test" der Wert von sein $test eher als die tatsächliche Zeichenfolge '$test', Sie brauchen also nicht so viele .s.

Außerdem habe ich mich geirrt, wie die Prototypen funktionieren. Um einen Hash zu übergeben, verwenden Sie dies:

PrintAA("test", %hash);

Verwenden Sie dies: Um eine Hash -Referenz zu drucken, verwenden Sie Folgendes:

PrintAA("test", %$ref_to_hash);

Natürlich können Sie den Hash, von dem auf die bezeichnet wird, natürlich nicht ändern $ref_to_hash Weil Sie eine Kopie senden, aber Sie können einen RAW ändern %hash Weil Sie es als Referenz übergeben.

Argumente zu Funktionen werden in ein einzelnes Array (@_) abgeflacht. Es ist also normalerweise am einfachsten, Hashes zu verabschieden, um durch Bezugnahme zu funktionieren.

Um einen Hash zu erstellen:

my %myhash = ( key1 => "val1", key2 => "val2" );

Um einen Verweis auf diesen Hash zu erstellen:

my $href = \%myhash

Zugriff auf diesen Hash durch Bezugnahme;

%$href

Also in deinem Sub:

my $myhref = shift;

keys %$myhref;

Alle anderen Antworten hier scheinen mir bisher ziemlich kompliziert zu sein. Wenn ich die Perl -Funktion schreibe, "erweitere" ich normalerweise alle bestandenen Argumente in der ersten Zeile der Funktion.

sub someFunction {
    my ( $arg1, $arg2, $arg3 ) = @_;

Dies ähnelt anderen Sprachen, in denen Sie Funktionen als deklarieren

... someFunction ( arg1, arg2, arg3 )

Und wenn Sie es so tun und den Hash als das letzte Argument bestehen, werden Sie ohne Tricks oder besondere Magie in Ordnung sein. Z.B:

sub testFunc {
    my ( $string, %hash ) = @_;
    print "$string $hash{'abc'} $hash{'efg'} $string\n";
}

my %testHash = (
    'abc' => "Hello",
    'efg' => "World"
);
testFunc('!!!', %testHash);

Die Ausgabe ist wie erwartet:

!!! Hello World !!!

Dies funktioniert, weil in Perl Argumenten immer als eine Reihe von Skalarwerten übergeben werden, und wenn Sie einen Hash übergeben, werden diesem Array der Schlüsselwert/die Paare hinzugefügt. In der obigen Stichprobe übergab die Argumente an die Funktion als Array (@_) sind in der Tat:

'!!!', 'abc', 'Hello', 'efg', 'World'

und '!!!' ist einfach zugeordnet zu %string, während %hash "Swallows" alle anderen Argumente und interpretieren immer einen als Schlüssel und den nächsten als Wert (bis alle Elemente aufgebraucht sind).

Sie können nicht mehrere Hashes auf diese Weise bestehen, und der Hash kann nicht das erste Argument sein, da es sonst alles verschluckt und alle anderen Argumente nicht zugewiesen wird.

Natürlich funktioniert genau die gleichen Funktionen für Array als letztes Argument. Der einzige Unterschied besteht darin, dass Arrays nicht zwischen Schlüssel und Werten unterscheiden, denn alle übrig gebliebenen Argumente sind Werte und werden einfach auf das Array gedrückt.

Verwenden Sie das lobende Sub, um Hash oder Hashref zu bekommen - was auch immer bestanden :)

sub get_args { ref( $_[0] ) ? shift() : ( @_ % 2 ) ? {} : {@_}; }
sub PrintAA
{
  my $test = shift;
  my $aa = get_args(@_);;
  #then
  $aa->{somearg} #do something
  $aa->{anotherearg} #do something

}

Rufen Sie Ihre Funktion so auf:

printAA($firstarg,somearg=>1, anotherarg=>2)

Oder wie dieses (egal):

printAA($firstarg,{somearg=>1, anotherarg=>2})

Oder sogar so (egal):

my(%hash) = ( 'aaa' => 1, 'bbb' => 'balls', 'ccc' => \PrintAA );

PrintAA("test", %hash);

Prost!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top