web-dev-qa-db-fra.com

Qu'est-ce que "0 mais vrai" signifie à Perl?

Quelqu'un peut-il expliquer ce que signifie exactement la chaîne "0 mais vrai" signifie à Perl? Autant que je sache, cela équivaut à zéro dans une comparaison entière, mais évalue de vrai lorsqu'il est utilisé comme booléen. Est-ce correct? Est-ce un comportement normal de la langue ou est-ce une chaîne spéciale traitée comme un cas particulier dans l'interprète?

61
jkramer

C'est un comportement normal de la langue. Citant le perlsyn Manpage:

Le nombre 0, Les cordes '0' et "", la liste vide (), et undef sont tous faux dans un contexte booléen. Toutes les autres valeurs sont vraies. Négation d'une valeur réelle de ! ou not renvoie une fausse valeur spéciale. Lorsqu'il est évalué comme une chaîne, il est traité comme "", mais comme un nombre, il est traité comme 0.

Pour cette raison, il doit y avoir un moyen de retourner 0 À partir d'un appel système qui prévoit de retourner 0 comme une valeur de retour (réussie) et laissez un moyen de signaler un cas de défaillance en retournant une fausse valeur. "0 but true" sert à cette fin.

57
Chris Jester-Young

Parce qu'il est codé dans le noyau Perl de le traiter comme un nombre. Ceci est un hack pour faire des conventions de Perl et ioctl 's Conventions joue ensemble; de perldoc -f ioctl:

La valeur de retour de ioctl (et fcntl) est la suivante:

if OS returns:      then Perl returns:

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

Ainsi, Perl retourne true sur le succès et la fausse échec, mais vous pouvez toujours déterminer facilement la valeur réelle renvoyée par le système d'exploitation:

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

La chaîne spéciale "0 but true" est exempté de -w plaintes concernant des conversions numériques incorrectes.

52
geekosaur

De plus, à ce que dit les autres, "0 but true" est spécialisé dans la mesure où il ne prévoit pas dans le contexte numérique:

$ 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
45
moritz

La valeur 0 but true est un cas particulier à Perl. Bien que à vos simples yeux mortels, cela ne ressemble pas à un nombre, de sage et de tout savoir que Perl comprend que c'est vraiment un nombre.

Cela concerne le fait que lorsqu'un sous-programme perl retourne une valeur 0, il est supposé que la routine a échoué ou renvoyé une fausse valeur.

Imaginez que j'ai un sous-programme qui retourne la somme de deux nombres:

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 première déclaration ne mourra pas parce que le sous-programme retournera un 1. C'est bon. La deuxième déclaration mourra parce que le sous-programme ne sera pas capable d'ajouter vache à chien .

Et la troisième déclaration?

Hmmm, je peux ajouter 3 à -3. Je viens d'obtenir 0, mais mon programme mourra même si le sous-programme add fonctionnait!

Pour contourner cela, Perl considère 0 but true Pour être un nombre. Si mon ajoutez Les retours de sous-programme non seulement 0 , mais 0 mais vrai , ma troisième déclaration fonctionnera.

Mais est 0 mais vrai un zéro numérique? Essayez ceci:

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";

Yup, c'est zéro!

Le index Le sous-programme est un très vieux morceau de Perl et existait avant le concept de 0 mais vrai était autour. Il est supposé renvoyer la position de la sous-chaîne située dans la chaîne:

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

La dernière déclaration renvoie un -1. Ce qui signifie que si je l'ai fait:

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

Comme je le traite normalement avec des fonctions standard, cela ne fonctionnerait pas. Si j'utilisais "Barfoo" et "bar" comme je l'ai fait dans la deuxième déclaration, la clause else exécuterait, mais si j'utilisais "Barfoo" et "Fu" comme dans la troisième, le if la clause exécuterait. Pas ce que je veux.

Cependant, si le sous-programme index renvoyé 0 mais vrai pour la deuxième déclaration et undef pour la troisième déclaration, mon if/else clause aurait fonctionné.

32
David W.

Vous pouvez également voir la chaîne "0e0" utilisé dans le code Perl , et cela signifie la même chose, où 0e0 signifie juste 0 écrit en notation exponentielle. Cependant, étant donné que Perl ne considère que "0", '' ou undef comme faux, il évalue comme vrai dans un contexte booléen.

24
Andy Lester

C'est codé dur dans le code source de Perl, spécifiquement dans perl_grok_number_flags dans numeric.c .

Lecture de ce code J'ai découvert que la chaîne "Infinity" (Case Insensible) transmet également le test Look_Like_Number. Je ne savais pas ça.

12
Simon Whitaker

Dans un contexte entier, il évalue à 0 (la partie numérique au début de la chaîne) et est nulle. Dans un contexte scalaire, il s'agit d'une valeur non vide, elle est donc vraie.

  • if (int("0 but true")) { print "zero"; }

    (aucune sortie)

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

    (imprime vrai)

10
Daniel Papasian

signifie faux dans Perl (et d'autres langues liées à c). Pour la plupart, c'est un comportement raisonnable. Autres langues (Lua Par exemple) Traiter comme vrai et fournissez un autre jeton (souvent nil ou faux) pour représenter une valeur non réelle.

Un cas où la voie Perl ne fonctionne pas si bien, c'est lorsque vous souhaitez revenir un nombre ou, si la fonction échoue pour une raison quelconque, une fausse valeur. Par exemple, si vous écrivez une fonction qui lit une ligne d'un fichier et renvoie le nombre de caractères sur la ligne. Un usage commun de la fonction pourrait être quelque chose comme:

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

Notez que si le nombre de caractères sur une ligne particulière est égal à 0, la boucle tandis que se terminera avant la fin du fichier. Donc, la fonction caractères_in_line doit avoir une case spéciale 0 caractères et retour '0 mais vrai' à la place. De cette façon, la fonction fonctionnera comme prévu dans la boucle tandis que, mais renvoie également la réponse correcte doit être utilisée comme numéro.

Notez que ce n'est pas une partie intégrée de la langue. Il tire plutôt que cela profite de la capacité de Perl à interpréter une chaîne en tant que nombre. Donc, d'autres piqûres sont parfois utilisées à la place. DBI Utilisations "0e0", par exemple. Lorsqu'il est évalué dans le contexte numérique, ils retournent , mais dans le contexte booléen, faux.

9
Jon Ericson

Un autre exemple de "0 mais vrai":

Le module DBI utilise "0E0" comme valeur de retour pour mettre à jour ou supprimer des requêtes qui n'affectent aucun enregistrement. Il évalue comme vrai dans un contexte booléen (indiquant que la requête a été exécutée correctement) et à 0 dans un contexte numérique indiquant qu'aucun enregistrement n'a été modifié par la requête.

4
kixx

Lorsque vous souhaitez écrire une fonction qui retourne une valeur entière, ou FALSE ou se défendre (C'est-à-dire pour le cas d'erreur), vous devez alors faire attention à la valeur zéro. Le retour est faux et ne doit pas indiquer la condition d'erreur, donc renvoyer "0 mais vrai" rend la fonction de retour de la fonction true tout en repoussant la valeur zéro lorsque les mathématiques sont effectuées.

3
andy

La chaîne `` 0 mais vrai '' est toujours un cas particulier:

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

donnez ce qui suit: (Notez le `` Avertissement ''!)

'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: ||

... Et n'oubliez pas 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. ...
2
F. Hauri