2017-02-07 4 views
3

Ich habe gerade mit der Arbeit mit einem neuen Team neuen Ort begonnen. Sie sagten mir, dass wir ref anstelle von Wert in unseren Perl-Modulen zurückgeben. Auch ich sah etwas wie return +{foo=>'bar'}; and return {foo=>'bar'}; Was ist der Unterschied? Und ob Ref oder Wert zurückgeben?Unterschied zwischen der Rückgabe + {} oder {} in Perl von einer Funktion, und Rückgabe ref oder Wert

+4

Es wird gelegentlich verwendet, um zwischen einer HASH-Referenz und einem BLOCK-Ausdruck zu disambiguieren. Sie können mehr darüber unter ['perldoc perlref'] (http://perldoc.perl.org/perlref.html) lesen –

+3

Oh mein Gott. Perl-Standards, geschrieben von Nicht-Perl-Programmierern! Sicherlich müssen Sie nicht 'return \ 1 'schreiben? Aber immer wiederkehrende Hash- oder Array-Referenzen sind ein Rezept für Speicherlecks. – Borodin

+0

"return ref statt value" ... das habe ich gesehen. Das bedeutet normalerweise, dass der Rückgabewert * immer * eine Referenz ist (egal ob Hash, Array usw.), auch wenn er leer ist. Wenn alles in Ordnung ist, erhalten Sie möglicherweise eine aufgefüllte Hash-Referenz, aber bei einem Fehler oder Erfolg, aber nichts erreicht, eine leere ref '{}' (Hash-Ref in diesem Fall). Dann könnte der Aufrufer: 'if (! Exists $ return -> {expected}) {do_something(); ...} ' – stevieb

Antwort

10

Die + ist dort völlig nutzlos.


Zuerst einige Hintergrund.

Die Perl-Sprache hat Unklarheiten. Nehmen Sie zum Beispiel

sub f { 
    { }  # Is this a hash constructor or a block? 
} 

{ } ist gültige Syntax für einen Block ("bare-Loop").
{ } ist gültige Syntax für einen Hash-Konstruktor.
Und beide sind als Aussage erlaubt!

Also muss Perl raten. Perl wird normalerweise richtig geschätzt, aber nicht immer. Sie können es "Hinweise" geben. Unary-+ kann dazu verwendet werden. Unary- + ist ein vollständig transparenter Operator; es macht gar nichts. Es muss jedoch ein Ausdruck (keine Aussage) folgen. { } hat nur eine mögliche Bedeutung als Ausdruck.

+{ } # Must be a hash constructor. 

In ähnlicher Weise können Sie Perl dazu bringen, den anderen Weg zu erraten.

{; } # Perl looks head, and sees that this must be a block. 

Hier ist ein Beispiel, wo Perl falsche Vermutungen:

map { {} } 1..5 # ok. Creates 5 hashes and returns references to them. 
map {}, 1..5  # XXX Perl guesses you were using "map BLOCK LIST". 
map +{}, 1..5  # ok. Perl parses this as "map EXPR, LIST". 

Wie für den Code in der Frage, return muss durch einen Ausdruck (wenn überhaupt) verfolgt werden, so gibt es nur eine mögliche Interpretation für return { ... };, so dass die + dort völlig nutzlos ist.

Die meisten Menschen disambiguieren nur bei Bedarf. Andere könnten + hinzufügen, wenn es mehrdeutig ist (selbst wenn Perl richtig rät). Aber das ist das erste Mal, dass ich von + vor jedem Hash-Konstruktor gehört habe.

+1

Sehr schöne Erklärung, die die Mehrdeutigkeit aus der Mehrdeutigkeit entfernt. – stevieb

+0

Beachten Sie, dass seit 'map {}, 1..5;' nur eine gültige Interpretation hat, damit Perl herausfinden kann, was Sie gemeint haben, anstatt zu raten. 1) Das geht davon aus, dass niemand Syntaxfehler macht, und 2) Wenn Sie disambiguieren, disamiguieren Sie nicht nur für Perl, sondern auch für den Leser. Kurz gesagt, es ist am besten, die Bedeutung von Tokens so schnell wie möglich zu kennen. – ikegami

9

Was ist der Unterschied?

Das sind genau die gleichen, so dass die + ist fremd. Sie können dies sehen von B::Deparse mit:

$ perl -MO=Deparse -e'sub foo { return { foo => "bar" } }' 
sub foo { 
    return {'foo', 'bar'}; 
} 
-e syntax OK 

$ perl -MO=Deparse -e'sub foo { return +{ foo => "bar" } }' 
sub foo { 
    return {'foo', 'bar'}; 
} 
-e syntax OK 

In beiden Fällen sind Sie eine Referenz auf einen Hash zurück.


Als Hunter McMillen sagte in einem Kommentar, gibt es einige Fälle, in denen Sie den einstelligen + Operator verwenden müssen, um Unklarheiten zu lösen.

$ perl -e'@a = map { $_ => "foo" }, 1..3' # { ... } treated as a block 
syntax error at -e line 1, near "}," 
Execution of -e aborted due to compilation errors. 

$ perl -e'@a = map +{ $_ => "foo" }, 1..3' # { ... } treated as a hashref 

Und ob zurückzukehren ref oder Wert:

zum Beispiel zwischen einem anonymen Hash und einem Block in einem map zu unterscheiden?

Mit „einen Wert zurückgibt:“ Ich nehme an, Ihre Mitarbeiter so etwas wie dies bedeuten:

sub foo { 
    my %bar = (baz => 'qux'); 
    return %bar; # as opposed to \%bar 
} 

my %hash = foo(); 

Subroutinen nur eine Liste der Skalare zurückkehren kann, so ist dies entspricht in etwa

my %hash = ('baz', 'qux'); 

Wenn %bar viele Elemente enthält, wird das Kopieren dieser Liste teuer. Daher kann es besser sein, stattdessen eine Referenz zu senden:

sub foo { 
    my %bar = (baz => 'qux'); 
    return \%bar; 
} 

my $hashref = foo(); 
+2

Hinweis: Deparse ist eine gute Referenz, aber es ist nicht endgültig. Wenn Sie einen definitiven Vergleich wünschen, können Sie 'diff -u <(Perl -MO = Concise, -exec, foo -e'sub foo {retour {foo =>" bar "}} '2> & 1) <(perl -MO = Concise, -exec, foo -e'sub foo {return + {foo => "bar"}} '2> & 1) '. – ikegami

Verwandte Themen