perl - repositorio - r studio packages
¿Por qué no me da nada en Perl? (5)
Aquí hay un addendum a las otras grandes respuestas que ya ha recibido.
No es no no
Considere el siguiente código que prueba cada uno de los operadores ''no'' de Perl:
#!/usr/bin/perl
use strict;
use warnings;
for( ''!1'', ''not 1'', ''~0'' ) {
my $value = eval;
my $zero_plus = 0 + $value;
print join "/n",
"/nExpression: $_",
"Value: ''$value''",
"Defined: " . defined $value,
"Length: " . length($value),
"Plus: " . +$value,
"Plus Zero: ''$zero_plus''",
'''';
}
print "/nTest addition for a literal null string: ";
print 0+'''', "/n";
use Scalar::Util qw(dualvar);
{ # Test a dualvar
my $value = dualvar 0, '''';
my $zero_plus = 0+$value;
print join "/n",
"/nExpression: dualvar",
"Value: ''$value''",
"Defined: " . defined $value,
"Length: " . length($value),
"Plus: " . +$value,
"Plus Zero: ''$zero_plus''",
'''';
}
Ejecutarlo resulta en lo siguiente. Observe el mensaje de advertencia:
Argument "" isn''t numeric in addition (+) at test.pl line 21.
Expression: !1
Value: ''''
Defined: 1
Length: 0
Plus:
Plus Zero: ''0''
Expression: not 1
Value: ''''
Defined: 1
Length: 0
Plus:
Plus Zero: ''0''
Expression: ~0
Value: ''4294967295''
Defined: 1
Length: 10
Plus: 4294967295
Plus Zero: ''4294967295''
Test addition for a literal null string: 0
Expression: dualvar
Value: ''''
Defined: 1
Length: 0
Plus:
Plus Zero: ''0''
De esto aprendemos varias cosas.
Los dos primeros elementos no son tan emocionantes:
-
!1
ynot 1
comportan básicamente de la misma manera. - Como era de esperar,
~1
es diferente (no es el bit a bit).
Ahora, el artículo interesante:
- Si bien recibimos una advertencia para la línea 21 (
0+''''
), no se genera una advertencia cuando agregamos0+!1
.
Se necesitan dos para enredar
Algo raro está ocurriendo, y esa pesadez tiene que ver con contextos escalares especiales en Perl. En este caso, la distinción entre contextos numéricos y de cadena. Y la capacidad de crear una variable que tiene diferentes valores en cada contexto, también conocida como una variable dual.
Parece que !1
devuelve una variable dual que devuelve 0 en contexto numérico y la cadena nula en contexto de cadena.
La prueba dualvar al final muestra que una dualvar casera funciona de la misma manera que !1
.
Pero es una buena cosa
Al igual que muchas características de Perl, las variables duales parecen al principio desafiar las expectativas y pueden ser confusas. Sin embargo, al igual que esas otras características, utilizadas apropiadamente hacen la vida mucho más fácil.
Por lo que sé, una variable dual de 0
y ''''
es el único valor definido que devolverá falso en todos los contextos escalares. Así que es un valor de retorno muy sensible para !1
. Se podría argumentar que undef
es un buen resultado falso, pero entonces una variable no inicializada no se distingue de un valor falso. Además, los intentos de imprimir o agregar los resultados de los valores booleanos estarían plagados de advertencias innecesarias.
¡Otro famoso dualvar es $!
o $OS_ERROR
si usas use English
. En forma numérica, obtiene el código de error, en forma de cadena, el código de error se traduce para usted.
No es nada, está vacío, pero no es nada
Entonces, en resumen, no está obteniendo nada, no está obteniendo una cadena vacía y no está obteniendo cero.
Obtiene una variable que es tanto una cadena vacía como 0 al mismo tiempo.
Esto es extraño. El seguimiento:
$sum = !0;
print $sum;
imprime 1 como es de esperar. Pero esto
$sum = !1;
print $sum;
imprime nada ¿Por qué?
El El operador hace operaciones booleanas. ""
(La cadena vacía) es tan false
como 0
es. 1
es un true
valor conveniente. !
No debe confiarse en que haga algo más que producir algún valor true
/ false
. Confiar en el valor exacto más allá de eso es peligroso y puede cambiar entre versiones de Perl.
Los operadores que solo devuelven un resultado booleano siempre devolverán 1 para verdadero y un valor falso especial que está "" en contextos de cadena pero 0 en contextos numéricos.
Ten cuidado: lo que has escrito no está haciendo lo que crees que está haciendo. Recuerda, Perl no tiene ningún tipo de datos booleano real. Tiene escalares, hashes, listas y referencias. La forma en que maneja los valores verdaderos / falsos, entonces, es contextual. Todo se evalúa como "verdadero" en perl, excepto las variables no definidas, la lista vacía, la cadena vacía y el número 0.
Lo que hace su código, entonces, es tomar el inverso de un valor que se evalúa como "falso", que puede ser cualquier cosa que no esté en la lista anterior. Por convención y por simplicidad, Perl devuelve 1 (aunque no debe confiar en eso; podría muy bien devolver una lista que contenga una serie de números aleatorios, porque eso también se evaluará como "verdadero").
Algo similar sucede cuando pides la inversa de un valor que se evalúa como "verdadero". Lo que realmente se está imprimiendo no es "nada", es la cadena vacía (''''), que, como mencioné, se evalúa como "falso" en expresiones booleanas. Puede comprobar esto:
print "This evaluates to false/n" if( (!1) eq '''');
Si está preguntando por qué Perl escupe la cadena vacía en lugar de uno de los otros valores "falsos", probablemente se deba a que Perl está hecho para manejar cadenas y esa es una cadena perfectamente razonable para devolver.
Ver perldoc perlsyn :
Verdad y falsedad
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 verdadero valor por! o no devuelve un valor falso especial. Cuando se evalúa como una cadena, se trata como '''', pero como un número, se trata como 0.
Allí, si imprime el valor como un número, obtendrá 0
lugar de la cadena vacía:
printf "%d/n", $_ for map { !$_ } (1, 0);
o
print 0 + $_, "/n" for map { !$_ } (1, 0);
Comparar esos con
printf "%s/n", $_ for map { !$_ } (1, 0);
y
print $_, "/n" for map { !$_ } (1, 0);