2010-08-09 5 views
8

Czytam „początku” książki Perl, i to daje te dwa oświadczenia:Lista Operator Pierwszeństwo w Perlu

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

Pierwsza linia drukuje nic z nowej linii, druga linia drukuje z 1 bez nowej linii.

Jestem zakłopotany z powodu wyniku. Według autora, druga wypowiedź daje wyjście dziwne, bo to tak jakby powiedzieć:

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

Jednak dlaczego to pierwsza wypowiedź nie to samo? Myślałem, że ma to coś wspólnego z priorytetem druku. Model & & ma wyższy priorytet niż drukowanie, więc najpierw jest oceniany, a następnie drukowany. Natomiast "i" ma niższy priorytet niż druk, więc 6> 3 zostanie wydrukowane, drukowanie zwróci 1, a następnie zostanie ocenione przy pomocy "i". Jednak to naprawdę nie ma sensu.

Przeczytałem dokumentację Perla o tym, jak działa priorytet dla operatorów list, ale nadal nie rozumiem tego przykładu. Czy możecie przeanalizować te dwa stwierdzenia i powiedzieć, co jest drukowane jako pierwsze? Czy możesz również wyjaśnić, co oznacza dokumentacja Perla, gdy wymienia operatorów list jako "lewą" i "prawą?" Dzięki.


Dziękuję wszystkim za odpowiedzi. Rozumiem to teraz. Rzeczywiście robiłem to, co powiedział CJM i myślę, że są operatorzy list lewych i prawostronnych. Teraz, gdy rozumiem, co to znaczy, rozumiem całą sprawę.

+0

ten kod wyświetla ostrzeżenia. i ma nawet funner zachowanie w Devel :: REPL – xenoterracide

+0

@xenoterracide, to nie ma być dobry kod Perla. Próbuje tylko zilustrować, jak działa pierwszeństwo. – cjm

+0

@ instymat w prawo ... chociaż zachowanie re.pl wydawało mi się na tyle złe, że mogłem zgłosić błąd. zobaczymy, co z tego wyniknie. – xenoterracide

Odpowiedz

12

Okay, na początek: operatory list są jednymi z rzeczy o najniższym priorytecie w perlu, ale tylko po ich prawej stronie. Pytasz, co to znaczy: cóż, zróbmy to proste. Załóżmy, że istnieje zestaw o nazwie foo. Nie ma znaczenia, co robi, ale jest tam. Możesz łatwo stworzyć taką rzecz z sub foo { map 10 * $_, @_ }, która zwraca każdy z jej argumentów pomnożoną przez dziesięć. Że z okazji:

print 1, 2, 3; jest równoważna print(1, 2, 3);
print foo 1, 2, 3; jest równoważna print(foo(1, 2, 3));
print 1, foo 2, 3; jest równoważna print(1, foo(2, 3));

Widzimy, że foo pożera tyle, ile to możliwe po prawej stronie - tylko koniec instrukcji (do tej pory ...) może ją zatrzymać. Gdyby napisać @array = (1, foo 2, 3);, który byłby równoważny z @array = (1, foo(2, 3));, ponieważ oczywiście kończące otaczanie nawiasów nadal obowiązuje.

Ponieważ przecinki mają również bardzo niski priorytet (tuż nad "Operatorami list (w prawo)"), możemy również umieścić dowolne wyrażenie, które chcemy w argumentach do a listop - to tylko sposób na upewnienie się, że Perl że nie musimy dodawać nawiasów przez większość czasu. Matematyka, operatory bitowe, porównania, a nawet dopasowania regex mają wyższy priorytet.

Jedyne rzeczy, które zrobić mają niższy priorytet są orkisz-out spójniki logiczne and, or, xor i not. Więc jeśli piszemy

foo 1, 2, 3 and 4; 

to znaczy (foo(1, 2, 3) and 4) - argumenty do foo przystanku na lewo od and.Wydaje się to głupie w contrived przykład, więc wróćmy go do wspólnego perl idiomu:

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

co odpowiada

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

która jest faktycznie dokładnie równoważne (i kompiluje się)

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

za pomocą formularza modyfikatora oświadczeń unless (który nie jest wcale operatorem, jest dozwolony tylko raz na jedno oświadczenie i pojawia się tylko na końcu wyciągu, więc nie robi ". t naprawdę w ogóle angażować się w pierwszeństwo, ale możesz uważać to za "niższe niż najniższe" pierwszeństwo w lewo).

W każdym razie, wracając do swojej oryginalnej próbki kodu - argumenty do print końcu tuż na lewo od and, a po prawej stronie and jest całkowicie odrębny wyraz przecinek - które w ogóle nic nie robi, bo to tylko kilka stałe 3 > 4 i "\n" ocenione w pustym kontekście.

+1

++: Gwiezdne wyjaśnienie! – Zaid

8

Oto jak te oświadczenia będzie wyglądać z pełnymi nawiasach:

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

> ma najwyższy priorytet, a następnie &&, następnie ,, następnie print, następnie and.

6 > 3 ocenia na 1. 3 > 4 jest wartością false, która w Perlu jest wartością specjalną, która wynosi 0 w kontekście liczbowym, ale pusty ciąg w kontekście ciągu znaków (jak tutaj). Tak więc ((6 > 3) && (3 > 4)) daje pusty ciąg.

W ten sposób pierwsze oświadczenie przekazuje 3 argumenty do print: "Test one: ", pusty ciąg i znak nowej linii. Drukuje każdy argument w kolejności.

Druga instrukcja przekazuje tylko 2 argumenty do print: "Test two: " i 1. Nowa linia nie zostanie wydrukowana, ponieważ nigdy nie została przekazana do print.

Nie jestem pewien, jak wyjaśnić "lewą" i "prawą" lepiej niż the docs. Ale może to cię mylą, ponieważ myślisz, że są "lista lewych op" i "lista praw ops". To nie znaczy, co to oznacza. Próbuje powiedzieć, że wszystko po prawej stronie operatora listy zostanie zinterpretowane jako argumenty dla tego operatora (chyba że trafisz na jeden z operatorów Boole'a o bardzo niskim priorytecie, takich jak and). Ale rzeczy po lewej stronie operatora listy nie są powiązane z tym operatorem listy.

+0

@hobbs: W jaki sposób nie jest poprawny? musikk i powiedziałem to samo, z wyjątkiem tego, że użyłem kilku dodatkowych paren (i jego teraz wycofanego twierdzenia, że ​​'3> 4' to' undef'). Dane wyjściowe 'perl -MO = Deparse, -p' są identyczne dla oryginalnych instrukcji w porównaniu do moich w pełni zendetyzowanych wersji. – cjm

+0

Przykro mi, wygląda na to, że źle odczytałem. – hobbs

+0

Jak to działa w przypadku operatorów testowania plików? Na przykład, używając ['Test :: Więcej'] (https://metacpan.org/pod/Test::Więcej) Napisałem ten test' ok (nie -e $ fn, 'plik nie istnieje') 'który jest przeciwieństwem tego, czego się spodziewałem. –

4

Jest tak jak mówisz, z wyjątkiem części "to nie ma sensu".

Pierwszym jest

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

a drugi

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

Jeśli włączysz ostrzeżenia (use warnings) pojawi się ostrzeżenie Useless use of a constant in void context ponieważ prawa strona and ocenia się na liście z elementami false i znak nowej linii, ale nigdy nie jest używany.

edytuj: Poprawiono moje roszczenie 3> 4 jest undef. Fałsz nie jest niepotrzebny. Jest zdefiniowany i nic nie drukuje.