2010-08-09 16 views
8

Ich lese das „Beginning Perl“ Buch, und es gibt diese zwei Aussagen:Liste Operator Präzedenz in Perl

print "Test one: ", 6 > 3 && 3 > 4, "\n"; 
print "Test two: ", 6 > 3 and 3 > 4, "\n"; 

Die erste Zeile druckt nichts mit einer neuen Zeile, die zweite Zeile druckt ein 1 mit keine neue Zeile

Ich bin verwirrt über die Ausgabe. Nach Ansicht des Autors, gibt die zweite Aussage seltsam ausgegeben, weil es einfach nur sagen, wie ist:

print ("Test two: ", 6 > 3) and 3 > 4, "\n"; 

Doch warum ist die erste Anweisung nicht das Gleiche? Ich dachte, es hätte etwas mit der Priorität des Drucks zu tun. Die & & hat eine höhere Priorität als der Druck, so dass zuerst ausgewertet und dann gedruckt wird. Während das "und" eine niedrigere Priorität als print hat, wird also 6> 3 gedruckt, print gibt eine 1 zurück, und dann wird das mit "and" ausgewertet. Das macht jedoch keinen Sinn.

Ich habe die Perl-Dokumentation gelesen, wie Vorrang für Listoperatoren funktioniert, aber ich verstehe dieses Beispiel immer noch nicht. Können Sie die beiden Aussagen sezieren und mir sagen, was zuerst gedruckt wird? Kannst du auch erklären, was die Perl-Dokumentation bedeutet, wenn sie Listenoperatoren als "links" und "rechts" bezeichnet? Vielen Dank.


Vielen Dank für Ihre Antworten. Ich verstehe es jetzt. Ich tat tatsächlich, was CJM sagte, und dachte, dass es Links und Rechts-Listen-Operatoren gibt. Jetzt, wo ich verstehe, was es bedeutet, verstehe ich die ganze Sache.

+0

Dieser Code gibt Warnungen aus. und hat sogar Spaß Verhalten in Devel :: REPL – xenoterracide

+0

@xenoterracide, es ist nicht beabsichtigt, gute Perl-Code sein. Es versucht nur zu veranschaulichen, wie die Präzedenz funktioniert. – cjm

+0

@cjm Richtig ... obwohl das Verhalten von re.pl falsch genug für mich schien, um einen Fehler zu melden. wir werden sehen, was daraus wird. – xenoterracide

Antwort

12

Okay, für den Anfang: List-Operatoren gehören zu den niedrigsten Präzedenzfälle in Perl, aber nur auf ihrer rechten Seite. Sie fragen, was das heißt: Nun, machen wir es einfach. Angenommen, es gibt eine Liste namens foo. Es ist egal, was es tut, aber es ist da. Sie können so etwas mit sub foo { map 10 * $_, @_ } erstellen, die jedes ihrer Argumente mit zehn multipliziert. Dass aus dem Weg:

print 1, 2, 3; entspricht print(1, 2, 3);
print foo 1, 2, 3; entspricht print(foo(1, 2, 3));
print 1, foo 2, 3; entspricht print(1, foo(2, 3));

Wir können sehen, dass foo verschlingt so viel nach oben wie möglich auf der rechten Seite - nur das Ende der Aussage (bis jetzt ...) kann es stoppen. Wenn wir @array = (1, foo 2, 3); schreiben würde das @array = (1, foo(2, 3)); äquivalent sein, da natürlich die umschließenden runden Klammern immer noch gelten.

Da Kommas auch sehr niedrige Priorität haben (knapp über "Listenoperatoren (rechts)"), können wir auch so ziemlich jeden Ausdruck in die Argumente eines Listop einfügen - das ist nur eine Möglichkeit dass wir die meiste Zeit keine Klammern hinzufügen müssen. Mathe, bitweise Operatoren, Vergleiche, sogar Regex-Übereinstimmungen haben höhere Priorität.

Die einzigen Dinge, die tun mit niedrigerer Priorität haben, sind die Dinkel-out Junktoren and, or, xor und not. Wenn wir also

foo 1, 2, 3 and 4; 

schreiben, die (foo(1, 2, 3) and 4) bedeutet - die Argumente zu foo Anschlag nach links von der and.Dies scheint in einem konstruiertes Beispiel albern, so läßt es sich in ein gemeinsames Perl-Idiom drehen:

open $fh, '<', $filename or die "$! opening $filename"; 

, den

entsprechen
(open($fh, '<', $filename) or die("$! opening $filename")); 

, die eigentlich genau das gleiche (und kompiliert)

die "$! opening $filename" unless open $fh, '<', $filename; 

mit dem Statement-Modifier-Formular unless (das ist überhaupt kein Operator, ist nur einmal pro Anweisung erlaubt, und kommt nur am Ende einer Anweisung, so ist es nicht t wirklich überhaupt Vorrang haben, aber Sie könnten es als "niedriger als niedrigste" Präzedenzrecht nach links betrachten.

Wie auch immer, zu Ihrem ursprünglichen Codebeispiel Rückkehr - die Argumente zu print Ende nur der and links und rechts von der and ist ein völlig separater Ausdruck Komma - die überhaupt nichts tut, weil es nur wenige ist Konstanten 3 > 4 und "\n" ausgewertet im void Kontext.

+1

++: Stellar Erklärung! – Zaid

8

Hier ist, wie diese Aussagen mit vollen Klammern aussehen:

print("Test one: ", ((6 > 3) && (3 > 4)), "\n"); 
print("Test two: ", (6 > 3)) and ((3 > 4), "\n"); 

> die höchste Priorität hat, dann &&, dann ,, dann print, dann and.

6 > 3 ergibt 1. 3 > 4 wertet false aus, was in Perl ein spezieller Wert ist, der in einem numerischen Kontext 0 ist, aber die leere Zeichenfolge in einem Zeichenfolgenkontext (wie hier). So liefert ((6 > 3) && (3 > 4)) die leere Zeichenfolge.

Somit übergibt die erste Anweisung 3 Argumente an print: "Test one: ", die leere Zeichenfolge und eine Zeilenumbruch. Es druckt jedes Argument der Reihe nach. Die zweite Anweisung übergibt nur 2 Argumente an print: "Test two: " und 1. Der Zeilenumbruch wird nicht gedruckt, da er nie an print übergeben wurde.

Ich bin nicht sicher, wie man "nach links" und "nach rechts" besser als the docs erklären kann. Aber vielleicht verwirren Sie, dass Sie denken, dass es "Links-Listen-Ops" und "Rechts-Listen-Ops" gibt. Das ist nicht was es bedeutet. Es versucht zu sagen, dass alles auf der rechten Seite eines Listenoperators als Argumente für diesen Operator interpretiert wird (es sei denn, Sie treffen einen der Booleschen Operatoren mit sehr niedriger Priorität wie and). Aber Dinge auf der linken Seite eines Listenoperators sind diesem Listenoperator nicht zugeordnet.

+0

@hobbs: In welcher Weise ist es nicht korrekt? Musikk und ich haben dasselbe gesagt, außer dass ich ein paar zusätzliche Parens benutzt habe (und seine jetzt zurückgenommene Behauptung, '3> 4 'sei' undef '). Die Ausgabe von 'perl -MO = Deparse, -p 'ist für die ursprünglichen Anweisungen im Vergleich zu meinen vollständig geklammerten Versionen identisch. – cjm

+0

Es tut mir leid, es sieht so aus, als hätte ich es falsch gelesen. – hobbs

+0

Wie funktioniert das bei Dateitestbetreibern? Zum Beispiel, mit ['Test :: More'] (https://metacpan.org/pod/Test::More) schrieb ich diesen Test' ok (nicht -e $ fn, 'Datei existiert nicht') 'was macht das Gegenteil von dem, was ich erwartet habe .. –

4

Es ist wie du sagst, außer für den "das macht keinen Sinn" -Teil.

Die erste ist

print "Test one: ", (6 > 3 && 3 > 4), "\n"; 

und die zweite

(print "Test two: ", 6 > 3) and (3 > 4, "\n"); 

Wenn Sie auf Warnungen drehen (use warnings) erhalten Sie die Warnung Useless use of a constant in void context, weil die rechte Seite des and mit Elementen in eine Liste auswertet false und ein Newline aber wird nie benutzt.

bearbeiten: Korrigiert meine 3> 4 ist undef Anspruch. Falsch ist nicht undef. Es ist definiert und druckt nichts.