2010-08-09 6 views
8

Estoy leyendo el libro "A partir de Perl", y da estas dos afirmaciones:Lista Precedencia de operadores en Perl

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

La primera línea se imprime nada con una nueva línea, la segunda línea imprime un 1 con no hay una nueva línea

Estoy confundido acerca de la salida. Según el autor, la segunda sentencia da salida raro porque es como decir:

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

Sin embargo, ¿por qué es la primera declaración no es lo mismo? Pensé que tenía algo que ver con la precedencia de la impresión. El & & tiene mayor prioridad que la impresión, por lo que se evalúa primero y luego se imprime. Mientras que el "y" tiene una prioridad menor que la impresión, entonces 6> 3 se imprimirá, la impresión devuelve un 1, y luego se evalúa con el "y". Sin embargo, esto realmente no tiene sentido.

He leído la documentación de Perl sobre cómo funciona la precedencia para los operadores de listas, pero todavía no entiendo este ejemplo. ¿Pueden ustedes diseccionar las dos declaraciones y decirme qué se imprime primero? ¿Puede explicar también qué significa la documentación de Perl cuando menciona que los operadores de listas son "izquierdos" y "derechos"? Gracias.


Muchas gracias a todos por sus respuestas. Lo entiendo ahora De hecho, estaba haciendo lo que cjm dijo y pensando que hay operadores de listas hacia la izquierda y hacia la derecha. Entonces, ahora que entiendo lo que significa, lo entiendo todo.

+0

Este código imprime advertencias. y tiene un comportamiento aún más funesto en Devel :: REPL – xenoterracide

+0

@xenoterracide, no pretende ser un buen código Perl. Solo trata de ilustrar cómo funciona la precedencia. – cjm

+0

@cjm correcto ... aunque el comportamiento de re.pl me pareció lo suficientemente malo como para que yo le presente un error. veremos qué viene de eso. – xenoterracide

Respuesta

12

Bien, para empezar: los operadores de listas se encuentran entre los elementos de menor precedencia en Perl, pero solo en su lado derecho. Usted pregunta qué significa eso: bueno, hagámoslo simple. Supongamos que hay una listop llamada foo. No importa lo que haga, pero está ahí. Puede crear fácilmente tal cosa con sub foo { map 10 * $_, @_ }, que devuelve cada uno de sus argumentos multiplicado por diez. Que fuera del camino:

print 1, 2, 3; es equivalente a print(1, 2, 3);
print foo 1, 2, 3; es equivalente a print(foo(1, 2, 3));
print 1, foo 2, 3; es equivalente a print(1, foo(2, 3));

Podemos ver que foo engulle todo lo que puede en el lado derecho - solo el final de la declaración (hasta ahora ...) puede detenerlo. Si escribimos @array = (1, foo 2, 3); que sería equivalente a @array = (1, foo(2, 3)); porque, por supuesto, todavía se aplica la terminación del paréntesis circundante.

Dado que las comas también son de muy baja prioridad (justo arriba de "Operadores de listas (hacia la derecha)"), también podemos poner cualquier tipo de expresión que deseamos en los argumentos: ¡esto es solo una manera de asegurarse! que no tenemos que agregar paréntesis la mayor parte del tiempo. Matemáticas, operadores bit a bit, comparaciones, incluso coincidencias de expresiones regulares tienen mayor prioridad.

Las únicas cosas que hacer tienen menor prioridad son los conectivos lógicos deletreados and, or, xor y not. Así que si escribimos

foo 1, 2, 3 and 4; 

que significa (foo(1, 2, 3) and 4) - los argumentos a foo parada a la izquierda de la and.Esto parece tonto en un ejemplo inventado, así que vamos a convertirlo en un lenguaje Perl común:

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

lo que equivale a

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

que en realidad es exactamente equivalente a (y compila a)

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

usando el formulario de modificación de estado de unless (que no es un operador en absoluto, solo se permite una vez por extracto, y solo aparece al final de un extracto, por lo que no t realmente tiene prioridad, pero podría considerarla como una prioridad "más baja que la más baja" hacia la izquierda).

Así que de todos modos, volviendo a su muestra de código original - los argumentos a print final justo a la izquierda de la and, ya la derecha de la and es una expresión coma completamente separados - que no hace nada en absoluto, porque es sólo unos pocos las constantes 3 > 4 y "\n" evaluadas en contexto vacío.

+1

++: explicación estelar! – Zaid

8

Así es como esos estados se vería con paréntesis completos:

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

> tiene la prioridad más alta, entonces &&, entonces ,, entonces print, entonces and.

6 > 3 evalúa a 1. 3 > 4 evalúa como falso, que en Perl es un valor especial que es 0 en un contexto numérico pero la cadena vacía en un contexto de cadena (como aquí). Entonces ((6 > 3) && (3 > 4)) produce la cadena vacía.

Por lo tanto, la primera instrucción pasa 3 argumentos a print: "Test one: ", la cadena vacía y una nueva línea. Imprime cada argumento en orden.

La segunda instrucción solo pasa 2 argumentos a print: "Test two: " y 1. La nueva línea no se imprime porque nunca pasó a print.

No estoy seguro de cómo explicar "hacia la izquierda" y "hacia la derecha" mejor que the docs. Pero quizás lo que te confunde es que estás pensando que hay "operaciones de lista hacia la izquierda" y "operaciones de lista hacia la derecha". Eso no es lo que significa. Intenta decir que todo lo que está en el lado derecho de un operador de lista se interpreta como los argumentos para ese operador (a menos que aciertes uno de los operadores booleanos de muy baja prioridad como and). Pero las cosas en el lado izquierdo de un operador de lista no están asociadas con ese operador de lista.

+0

@hobbs: ¿De qué manera no es correcto? musikk y yo dijimos lo mismo, excepto que usé algunos parens extra (y su afirmación ahora retractada de que '3> 4' es' undef'). La salida de 'perl -MO = Deparse, -p' es idéntica para las declaraciones originales en comparación con mis versiones completamente entre paréntesis. – cjm

+0

Lo siento, parece que leí mal. – hobbs

+0

¿Cómo funciona esto en el caso de los operadores de prueba de archivos? Por ejemplo, usando ['Test :: More'] (https://metacpan.org/pod/Test::More) escribí esta prueba' ok (no -e $ fn, 'el archivo no existe') 'que hace lo contrario de lo que esperaba ... –

4

Es como usted dice, excepto por la parte "esto no tiene sentido".

La primera es

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

y el segundo

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

Si enciende advertencias (use warnings) se obtiene la advertencia Useless use of a constant in void context porque el lado derecho de la and como resultado una lista con los elementos falso y una nueva línea pero nunca se usa.

editar: Corregido mi 3> 4 es undef demanda. Falso no es undef. Está definido e imprime nada.

Cuestiones relacionadas