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?

Foi útil?

Solução

É um comportamento normal da linguagem. Citando o perlsyn manpage:

O 0 número, '0' cordas e "", a lista vazia () e undef são todas falsas em um contexto booleano. Todos os outros valores são verdadeiras. Negação de um verdadeiro valor por ! ou not retorna um valor falso especial. Quando avaliada como uma string é tratado como "", mas como um número, é tratadas como 0.

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 (e fcntl) é 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. ...
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top