O que significa “0, mas é verdade” significa em Perl?
Pergunta
Alguém pode explicar o que exatamente a string "0, mas é verdade" significa em Perl? Tanto quanto eu entendo, é igual a zero, em uma comparação inteiro, mas avalia a verdade quando usado como um booleano. Isso é correto? É este um comportamento normal da linguagem ou isso é uma seqüência especial tratado como um caso especial no interpretador?
Solução
É um comportamento normal da linguagem. Citando o perlsyn
manpage:
O
0
número,'0'
cordas e""
, a lista vazia()
eundef
são todas falsas em um contexto booleano. Todos os outros valores são verdadeiras. Negação de um verdadeiro valor por!
ounot
retorna um valor falso especial. Quando avaliada como uma string é tratado como""
, mas como um número, é tratadas como0
.
Devido a isso, é preciso haver uma maneira de voltar 0
de uma chamada de sistema que espera voltar 0
como um (bem sucedida) valor de retorno, e deixar uma maneira de sinalizar um caso de falha por realmente retornar um valor falso. "0 but true"
serve esse propósito.
Outras dicas
Porque é codificado no núcleo Perl para tratá-lo como um número. Este é um hack para fazer convenções do Perl e convenções de ioctl
jogar juntos; de perldoc -f ioctl
:
O valor de retorno de
ioctl
(efcntl
) é a seguinte:if OS returns: then Perl returns: -1 undefined value 0 string "0 but true" anything else that number
Assim Perl retorna true em caso de sucesso e falso em caso de falha, mas você ainda pode facilmente determinar o valor real retornado pelo sistema operacional:
$retval = ioctl(...) || -1; printf "System returned %d\n", $retval;
O
"0 but true"
corda especial é isenta de queixas-w
sobre as conversões numéricas impróprias.
Adicionalmente ao que outros disseram, "0 but true"
é especial-encaixotado na medida em que não avisá em 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
O valor 0 but true
é um caso especial em Perl. Embora a seus meros olhos mortais, ele não se parece com um número, sábio e todo Perl sabendo entende que realmente é um número.
Tem a ver com o fato de que, quando uma sub-rotina Perl retorna um valor 0, presume-se que a rotina de falha ou retornou um valor falso.
Imagine que eu tenha uma sub-rotina que retorna a soma de dois 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));
A primeira declaração não vai morrer porque a sub-rotina retornará um 1
. Isso é bom.
A segunda instrução vai morrer porque a sub-rotina não será capaz de adicionar vaca e cão .
E, a terceira afirmação?
Hmmm, eu posso adicionar 3
para -3
. Acabei de chegar 0
, mas depois o meu programa vai morrer mesmo que a sub-rotina add
funcionou!
Para contornar este problema, Perl considera 0 but true
ser um número. Se o meu Adicionar sub-rotina retorna não só 0 , mas 0, mas é verdade , a minha terceira declaração vai funcionar.
Mas é 0, mas é verdade um zero numérico? Tente isto:
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";
Sim, é zero!
O índice sub-rotina é uma peça muito antiga de Perl e existia antes do conceito de 0, mas é verdade estava por perto. É suposto para retornar a posição da substring localizado na string:
index("barfoo", "foo"); #This returns 3
index("barfoo", "bar"); #This returns 0
index("barfoo", "fu"); #This returns ...uh...
A última statment retorna um -1
. O que significa que se eu fizesse isso:
if ($position = index($string, $substring)) {
print "It worked!\n";
}
else {
print "If failed!\n";
}
Como eu faço normalmente com funções padrão, que não iria funcionar. Se eu usei "barfoo" e "bar" como eu fiz no segundo declaração, a cláusula else
seria executado, mas se eu usei "barfoo" e "fu", como no terceiro, a cláusula if
seria executado. Não é o que eu quero.
No entanto, se a sub-rotina index
voltou 0, mas é verdade para a segunda instrução e undef
para a terceira declaração, meu cláusula if
/ else
teria funcionado.
Você também pode ver a cadeia "0E0" usado no código Perl , e significa a mesma coisa, onde 0E0 significa apenas 0 escrito em notação exponencial. No entanto, desde Perl considera apenas "0", '' ou undef como falsa, ele avalia a verdade em um contexto booleano.
É embutida no código-fonte do Perl, especificamente na Perl_grok_number_flags em numeric.c .
A leitura que o código eu descobri que a string "infinito" (case insensitive) passa o teste looks_like_number também. Eu não sabia disso.
Em um contexto inteiro, ele avalia a 0 (a parte numérica no início da string) e é zero. Em um contexto escalar, é um valor não vazio, então é verdade.
-
if (int("0 but true")) { print "zero"; }
(sem saída)
-
if ("0 but true") { print "true"; }
(impressões true)
0 meio falsos em Perl (e outras línguas relacionadas com C). Para a maior parte, isso é um comportamento razoável. Outros idiomas (Lua por exemplo) deleite 0 como verdadeiro e fornecer outro token (geralmente nil ou false ) para representar um valor não-verdadeiro.
Um caso em que a forma como Perl não funciona tão bem é quando você deseja retornar um número ou, se a função falhar por algum motivo, um valor falso. Por exemplo, se você escrever uma função que lê uma linha de um arquivo e retorna o número de caracteres na linha. Um uso comum da função poderia ser algo como:
while($c = characters_in_line($file)){
...
};
Observe que se o número de caracteres em uma linha particular é 0, o enquanto ciclo vai terminar antes do final do arquivo. Assim, o characters_in_line função deve especiais de casos 0 personagens e retorno '0, mas verdadeiros' em seu lugar. Dessa forma, a função vai funcionar como pretendido no enquanto loop, mas também retornar a resposta correta deve ser usado como um número.
Note que este não é um construído em parte da linguagem. Pelo contrário, aproveita a capacidade do Perl para interpretar uma string como um número. Assim, outras picadas são por vezes usados ??em seu lugar. DBI usos "0E0" , por exemplo. Quando avaliada no contexto numérico, eles retornam 0 , mas no contexto booleano, false .
As coisas que são falsas:
-
""
. -
"0"
. - Coisas que stringify àqueles.
"0 but true"
não é um desses, por isso não é falsa.
Além disso, Perl retornos "0 but true"
onde um número é esperado para sinalizar que uma função sucedido mesmo que ele retornou zero. sysseek é um exemplo de tal função de um. Desde se espera que o valor a ser utilizado como um número, Perl é codificado para considerá-lo a ser um número. Como resultado, há avisos são emitidos quando ele é usado como um número, e looks_like_number("0 but true")
retorna verdadeiro.
Outros "verdadeiros zeros" pode ser encontrado em http://www.perlmonks.org/?node_id = 464548 .
Outro exemplo de "0, mas é verdade":
O módulo DBI usos "0E0" como um valor de retorno para atualizar ou excluir consultas que não afetaram nenhum registro. Ele avalia a verdade em um contexto booleano (o que indica que a consulta foi executado corretamente) e 0 em um contexto numérico que indica que nenhum registro foram alteradas pela consulta.
Eu só prova descobriu que a string "0, mas é verdade" é realmente construído para o intérprete, como algumas pessoas aqui já respondidas:
$ 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
Quando você quiser escrever uma função que retorna ou um valor inteiro, ou false ou undef (ou seja, para o caso de erro), então você tem que tomar cuidado para o valor zero. Retornando ela é falsa e não deve indicar a condição de erro, então retornando "0, mas é verdade" torna o valor de retorno de função TRUE enquanto ainda devolvendo o valor zero quando a matemática é feito sobre ele.
"0, mas é verdade" é uma string como qualquer outro, mas por causa da sintaxe do Perl pode servir a um propósito útil, ou seja, retornando inteiro zero de uma função sem o resultado que é "falso" (aos olhos do Perl).
E a necessidade de cadeia não ser "0, mas é verdade". "0, mas falsa" ainda é "verdadeira" no sentido booleano.
considerar:
if(x)
for x: yields:
1 -> true
0 -> false
-1 -> true
"true" -> true
"false" -> true
"0 but true" -> true
int("0 but true") ->false
O resultado de tudo isso é que você pode ter:
sub find_x()
e tenho esse código ser capaz de imprimir "0" como sua saída:
if($x = find_x)
{
print int($x) . "\n";
}
A string `` 0, mas é verdade '' ainda é um 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
Dê as seguintes: (! Observe o `` aviso '')
'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: ||
... e não se esqueça 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. ...