2011-08-05 16 views
5

estoy corriendo esta sola línea desde la línea de comandos:¿Por qué Perl imprime un valor que no espero después de incrementar?

perl -MList::Util=sum -E 'my $x = 0; say sum(++$x, ++$x)' 

¿Por qué dice "4" en lugar de "3"?

+0

Consulte también [¿Qué ejemplos de código perl pueden conducir a un comportamiento indefinido?] (Http://stackoverflow.com/questions/2176453/what-perl-code-samples-can-lead-to-undefined-behaviour) –

Respuesta

4

Está modificando $x dos veces en la misma declaración. De acuerdo con el docs, Perl no garantizará cuál es el resultado de estas declaraciones. Por lo tanto, puede ser "2" o "0".

+0

El pasaje en los documentos no es relevante. Dice que el resultado no está definido porque el orden de evaluación de operandos de los operadores no está definido. Si bien eso es cierto para '+' (utilizado en el ejemplo), no es para el operador de coma (utilizado por el OP). El LHS del operador de coma * * está documentado para ser evaluado antes del RHS. – ikegami

+0

Tenga en cuenta que, Perl tampoco garantiza el resultado en este caso, pero es por una razón diferente. Saber el resultado depende de saber si el incremento previo devuelve el escalar original (ahora modificado), o una copia del mismo, y * que * no está documentado. (Es el primero, fyi.) – ikegami

3

Porque ambos incrementos se ejecutan antes de que se calcule la suma.

Después de ejecutar ambos, x = 2.

2 + 2 = 4. 
+1

If esa era la razón, entonces 'suma (++ $ x, ++ $ x)' y 'suma (0 + ++ $ x, 0 + ++ $ x)' daría el mismo resultado. – ikegami

+1

@ikegami no es verdadero, porque la expresión '++ $ x' tiene una naturaleza lvalue pero la expresión' 0 + ++ $ x' tiene una naturaleza rvalue. Por lo general, eso es irrelevante ya que se están utilizando como valores r, pero en el caso indefinido en el que realizas dos preincrementos dentro de una llamada a función, sucede que tiene un efecto early-vs-late-bind-ish. – hobbs

+0

@hobbs, Usted dice que lo que dije no es verdad, sin embargo, usted acuerda con mi punto de vista que la naturaleza lvalue de la operación es la razón real. Esto está cubierto en detalle en mi respuesta. – ikegami

7

En primer lugar, tenga en cuenta que Perl pasa por referencia. Eso significa

sum(++$x, ++$x) 

es básicamente el mismo que

do { 
    local @_; 
    alias $_[0] = ++$x; 
    alias $_[1] = ++$x; 
    ∑ 
} 

Pre-incremento devuelve la propia variable en lugar de una copia del mismo *, lo que significa que tanto $_[0] y $_[1] son alias de $x. Por lo tanto, sum ve el valor actual de $x (2) para ambos argumentos.

Regla de oro: no modifique y lea un valor en la misma instrucción.

* — Esto no está documentado, pero usted se pregunta por qué Perl se comporta de la manera en que lo hace.

+0

+1 Creo que quisiste escribir "el valor actual de $ x' (2) '". – FMc

+0

@FMc, Gracias, corregido. – ikegami

Cuestiones relacionadas