Pregunta

¿Alguien puede explicar qué es exactamente la cadena " 0 pero verdadera " significa en Perl? Por lo que entiendo, es igual a cero en una comparación de enteros, pero se evalúa como verdadero cuando se usa como booleano. ¿Es esto correcto? ¿Es este un comportamiento normal del idioma o se trata de una cadena especial tratada como un caso especial en el intérprete?

¿Fue útil?

Solución

Es el comportamiento normal del lenguaje. Citar la página perlsyn :

  

El número 0 , las cadenas '0' y " " , la lista vacía () y undef   son todos falsos en un contexto booleano. Todos los demás valores son verdaderos. Negación   de un valor verdadero por ! o not devuelve un valor falso especial.   Cuando se evalúa como una cadena, se trata como " " , pero como un número, es   tratado como 0 .

Debido a esto, debe haber una forma de devolver 0 de una llamada del sistema que espera devolver 0 como un valor de retorno (exitoso), y dejar un forma de señalar un caso de falla devolviendo un valor falso " 0 pero verdadero " sirve ese propósito.

Otros consejos

Porque está codificado en el núcleo de Perl para tratarlo como un número. Este es un truco para hacer que las convenciones de Perl y las convenciones de ioctl se jueguen juntas; desde perldoc -f ioctl :

  

El valor de retorno de ioctl (y fcntl ) es el siguiente:

if OS returns:      then Perl returns:

    -1              undefined value
     0              string "0 but true"
anything else       that number
     

Por lo tanto, Perl devuelve verdadero en el éxito y falso en el fracaso, pero   Todavía puede determinar fácilmente el valor real devuelto por el   sistema operativo:

$retval = ioctl(...) || -1;
printf "System returned %d\n", $retval;
     

La cadena especial " 0 pero true " está exenta de las quejas de -w   sobre conversiones numéricas impropias.

Además de lo que otros han dicho, " 0 pero verdadero " está escrito de manera especial porque no advierte en el contexto numérico:

$ perl -wle 'print "0 but true" + 3'
3
$ perl -wle 'print "0 but crazy" + 3'
Argument "0 but crazy" isn't numeric in addition (+) at -e line 1.
3

El valor 0 pero true es un caso especial en Perl. Aunque para tus simples ojos mortales, no parece un número, sabio y sabiendo todo, Perl entiende que realmente es un número.

Tiene que ver con el hecho de que cuando una subrutina Perl devuelve un valor 0, se supone que la rutina falló o devolvió un valor falso.

Imagina que tengo una subrutina que devuelve la suma de dos números:

die "You can only add two numbers\n" if (not add(3, -2));
die "You can only add two numbers\n" if (not add("cow", "dog"));
die "You can only add two numbers\n" if (not add(3, -3));

La primera declaración no morirá porque la subrutina devolverá un 1 . Eso es bueno. La segunda declaración morirá porque la subrutina no podrá agregar cow a dog .

¿Y la tercera declaración?

Hmmm, puedo agregar 3 a -3 . Acabo de obtener 0 , pero luego mi programa morirá a pesar de que la subrutina add funcionó.

Para evitar esto, Perl considera que 0 pero true es un número. Si mi subrutina agregar devuelve no simplemente 0 , sino 0 pero verdadero , mi tercera declaración funcionará.

¿Pero es 0 pero cierto un cero numérico? Prueba estos:

my $value = "0 but true";
print qq(Add 1,000,000 to it: ) . (1_000_000 + $value) . "\n";
print "Multiply it by 1,000,000: " . 1_000_000 * $value . "\n";

Sí, ¡es cero!

La subrutina index es una pieza muy antigua de Perl y existía antes del concepto de 0, pero cierto estaba alrededor. Se supone que se devuelve la posición de la subcadena ubicada en la cadena:

index("barfoo", "foo");   #This returns 3
index("barfoo", "bar");   #This returns 0
index("barfoo", "fu");    #This returns ...uh...

La última declaración devuelve un -1 . Lo que significa que si hice esto:

if ($position = index($string, $substring)) {
   print "It worked!\n";
}
else {
   print "If failed!\n";
}

Como normalmente hago con las funciones estándar, no funcionaría. Si usé " barfoo " y " barra " como hice en la segunda declaración, la cláusula else se ejecutaría, pero si usara " barfoo " y " fu " como en el tercero, se ejecutaría la cláusula if . No es lo que quiero.

Sin embargo, si la subrutina index devolvió 0 pero true para la segunda declaración y undef para la tercera declaración, mi si La cláusula / else hubiera funcionado.

También puede ver la cadena " 0E0 " usado en el código Perl , y significa lo mismo, donde 0E0 solo significa 0 escrito en notación exponencial. Sin embargo, dado que Perl solo considera "0", "o undef como falso, se evalúa como verdadero en un contexto booleano.

Está codificado en el código fuente de Perl, específicamente en Perl_grok_number_flags en numeric.c .

Leyendo ese código, descubrí que la cadena " infinito " (no distingue mayúsculas y minúsculas) también pasa la prueba looks_like_number. No había sabido eso.

En un contexto entero, se evalúa en 0 (la parte numérica al principio de la cadena) y es cero. En un contexto escalar, es un valor no vacío, por lo que es cierto.

  • if (int (" 0 pero true ")) {print " cero " }

    (sin salida)

  • if (" 0 pero true ") {print " true " ;; }

    (imprime verdadero)

0 significa falso en Perl (y otros idiomas relacionados con C). En su mayor parte, eso es un comportamiento razonable. Otros idiomas (por ejemplo, Lua) tratan a 0 como verdadero y proporcionan otro token (a menudo nil o falso ) para representar un valor no verdadero.

Un caso en el que Perl no funciona tan bien es cuando desea devolver un número o, si la función falla por algún motivo, un valor falso. Por ejemplo, si escribe una función que lee una línea de un archivo y devuelve el número de caracteres en la línea. Un uso común de la función podría ser algo como:

while($c = characters_in_line($file)){
    ...
};

Observe que si el número de caracteres en una línea particular es 0, el bucle while finalizará antes del final del archivo. Por lo tanto, la función characters_in_line debe tener un caso especial de 0 caracteres y devolver '0 pero cierto' . De esa manera, la función funcionará como se pretende en el ciclo while , pero también devolverá la respuesta correcta si se usa como número.

Tenga en cuenta que esto no está integrado en parte del idioma. Más bien, aprovecha la capacidad de Perl para interpretar una cadena como un número. Así que a veces se usan otras picaduras en su lugar. DBI utiliza " 0E0 " , por ejemplo. Cuando se evalúan en contexto numérico, devuelven 0 , pero en contexto booleano, falso .

Cosas que son falsas:

  • " " .
  • " 0 " .
  • Cosas que se limitan a esas.

" 0 pero cierto " no es uno de esos, por lo que no es falso.

Además, Perl devuelve " 0 pero verdadero " donde se espera un número para indicar que una función tuvo éxito incluso si devolvió cero. sysseek es un ejemplo de dicha función. Dado que se espera que el valor se use como un número, Perl se codifica para considerarlo como un número. Como resultado, no se emiten advertencias cuando se usa como número, y looks_like_number (" 0 pero true ") devuelve true.

Otros " ceros verdaderos " se puede encontrar en http://www.perlmonks.org/?node_id=464548 .

Otro ejemplo de " 0 pero verdadero " ;:

El módulo DBI usa " 0E0 " como valor de retorno para consultas ACTUALIZADAS o BORRADAS que no afectaron ningún registro. Se evalúa como verdadero en un contexto booleano (lo que indica que la consulta se ejecutó correctamente) y en 0 en un contexto numérico que indica que la consulta no modificó ningún registro.

Acabo de encontrar una prueba de que la cadena " 0 pero verdadera " en realidad está integrado en el intérprete, como algunas personas aquí ya respondieron:

$ strings /usr/lib/perl5/5.10.0/linux/CORE/libperl.so | grep -i true
Perl_sv_true
%-p did not return a true value
0 but true
0 but true

Cuando desee escribir una función que devuelva un valor entero, o false o undef (es decir, para el caso de error), debe tener cuidado con la valor cero. Devolverlo es falso y no debería indicar la condición de error, por lo que se devuelve " 0 pero verdadero " hace que la función devuelva el valor verdadero mientras sigue devolviendo el valor cero cuando se realizan cálculos matemáticos en él.

" 0 pero cierto " es una cadena como cualquier otra, pero debido a la sintaxis de perl puede servir un propósito útil, a saber, devolver el entero cero desde una función sin que el resultado sea "falso" (a los ojos de perl).

Y la cadena no necesita ser " 0 sino verdadera " ;. " 0 pero falso " sigue siendo "verdadero" en el sentido booleano.

considere:

if(x)

for x:        yields:
1             -> true
0             -> false
-1            -> true
"true"        -> true
"false"       -> true
"0 but true"  -> true
int("0 but true") ->false

El resultado de todo esto es que puedes tener:

sub find_x()

y haga que este código pueda imprimir " 0 " como su salida:

if($x = find_x)
{
   print int($x) . "\n";
}

La cadena `0 pero cierta '' sigue siendo un caso especial:

for arg in "'0 but true'" "1.0*('0 but true')" \
           "1.0*('0 but false')" 0 1 "''" "0.0" \
           "'false'" "'Ja'" "'Nein'" "'Oui'" \
           "'Non'" "'Yes'" "'No'" ;do
    printf "%-32s: %s\n" "$arg" "$(
        perl -we '
            my $ans=eval $ARGV[0];
            $ans=~s/^(Non?|Nein)$//;
            if ($ans) {
                printf "true:  |%s|\n",$ans
            } else {
                printf "false: |%s|", $ans
          };' "$arg"
        )"
    done

indique lo siguiente: (observe la `` advertencia ''!)

'0 but true'                    : true:  |0 but true|
1.0*('0 but true')              : false: |0|
Argument "0 but false" isn't numeric in multiplication (*) at (eval 1) line 1.
1.0*('0 but false')             : false: |0|
0                               : false: |0|
1                               : true:  |1|
''                              : false: ||
0.0                             : false: |0|
'false'                         : true:  |false|
'Ja'                            : true:  |Ja|
'Nein'                          : false: ||
'Oui'                           : true:  |Oui|
'Non'                           : false: ||
'Yes'                           : true:  |Yes|
'No'                            : false: ||

... y no te olvides de RTFM!

man -P'less +"/0 but [a-z]*"' perlfunc

       ... "fcntl".  Like "ioctl", it maps a 0 return from the system call
           into "0 but true" in Perl.  This string is true in boolean
           context and 0 in numeric context.  It is also exempt from the
           normal -w warnings on improper numeric conversions. ...
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top