Question

Quelqu'un peut-il expliquer en quoi consiste exactement la chaîne " 0 mais vrai " signifie en Perl? Autant que je sache, il est égal à zéro dans une comparaison d'entiers, mais est évalué à true lorsqu'il est utilisé comme booléen. Est-ce correct? Est-ce un comportement normal du langage ou s'agit-il d'une chaîne spéciale traitée comme un cas particulier dans l'interpréteur?

Était-ce utile?

La solution

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

  

Le numéro 0 , les chaînes '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 vraie par ! ou pas renvoie une valeur fausse spéciale.   Lorsqu’il est évalué en tant que chaîne, il est traité en tant que "" ", mais en tant que nombre, il est   traité comme 0 .

Pour cette raison, il doit exister un moyen de renvoyer 0 à partir d'un appel système censé renvoyer 0 en tant que valeur de retour (réussie) et laisser un façon de signaler un cas d'échec en renvoyant une valeur fausse. "0 mais vrai" sert à cela.

Autres conseils

Parce qu'il est codé en dur dans le noyau Perl pour le traiter comme un nombre. C'est un hack pour faire en sorte que les conventions de Perl et les conventions de ioctl soient jouées ensemble; à partir 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 renvoie true en cas de succès et false en cas d'échec, mais vous   peut encore facilement déterminer 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 mais vraie" est exemptée des réclamations -w .   sur les conversions numériques incorrectes.

En plus de ce que d'autres ont dit, "0 mais vrai" est spécial, dans la mesure où il ne prévient pas dans un 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

La valeur 0 mais true est un cas particulier en Perl. Bien que, à vos yeux mortels, cela ne ressemble pas à un nombre, sage et tout le monde sait que Perl comprend que c’est vraiment un nombre.

Cela tient au fait que lorsqu'un sous-programme Perl renvoie une valeur 0, il est supposé que la routine a échoué ou a renvoyé une valeur fausse.

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 instruction ne mourra pas car le sous-programme renverra un 1 . C'est bon. La deuxième instruction mourra car le sous-programme ne pourra pas 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 la sous-routine add a fonctionné!

Pour contourner ce problème, Perl considère que 0 mais vrai est un nombre. Si mon add sous-routine renvoie non seulement 0 , mais 0 mais vrai , ma troisième instruction fonctionnera.

Mais 0 mais vrai est-il un zéro numérique? Essayez ces:

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

Oui, c'est zéro!

Le index est un très vieux morceau de Perl et existait avant le concept de 0 mais vrai était présent. 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 faisais ceci:

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

Comme je le fais normalement avec les fonctions standard, cela ne fonctionnerait pas. Si j'ai utilisé " barfoo " et " bar " comme dans la deuxième déclaration, la clause else serait exécutée, mais si j'utilisais "barfoo" et " fu " comme dans le troisième, la clause if serait exécutée. Pas ce que je veux.

Toutefois, si la sous-routine index a renvoyé 0 mais true pour la deuxième instruction et undef pour la troisième instruction, mon if / else aurait fonctionné.

Vous pouvez également voir la chaîne " 0E0 " utilisé dans le code Perl , et cela signifie la même chose, où 0E0 signifie simplement 0 écrit en notation exponentielle. Cependant, étant donné que Perl considère uniquement "0", ou "undef" comme étant faux, il est évalué à true dans un contexte booléen.

Il est codé en dur dans le code source de Perl, en particulier dans Perl_grok_number_flags in numeric.c .

En lisant ce code, j'ai découvert que la chaîne "infinity" (insensible à la casse) passe également le test looks_like_number. Je ne le savais pas.

Dans un contexte entier, il vaut 0 (la partie numérique au début de la chaîne) et vaut zéro. Dans un contexte scalaire, c'est une valeur non vide, donc c'est vrai.

  • if (int ("0 mais vrai")) {print ""; }

    (pas de sortie)

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

    (affiche vrai)

0 signifie false en Perl (et dans d'autres langages liés à C). Pour la plupart, c'est un comportement raisonnable. D'autres langues (Lua, par exemple) considèrent 0 comme vraies et fournissent un autre jeton (souvent rien ou faux ) pour représenter une valeur non vraie.

La méthode Perl ne fonctionne pas très bien si vous souhaitez renvoyer un nombre ou, si la fonction échoue pour une raison quelconque, une valeur fausse. Par exemple, si vous écrivez une fonction qui lit une ligne dans un fichier et renvoie le nombre de caractères de la ligne. Une utilisation courante de la fonction pourrait être quelque chose comme:

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

Notez que si le nombre de caractères d'une ligne est égal à 0, la boucle tandis que se termine avant la fin du fichier. Par conséquent, la fonction characters_in_line doit utiliser des caractères avec la casse spéciale 0 et renvoyer "0 mais true" à la place. Ainsi, la fonction fonctionnera comme prévu dans la boucle while , mais renverra également la réponse correcte si elle est utilisée sous forme de nombre.

Notez que cela ne fait pas partie intégrante du langage. Cela tire plutôt parti de la capacité de Perl à interpréter une chaîne comme un nombre. Donc, d'autres piqûres sont parfois utilisées à la place. DBI utilise par exemple "0E0" . Lorsqu'ils sont évalués dans un contexte numérique, ils renvoient 0 , mais dans un contexte booléen, false .

Ce qui est faux:

  • "" .
  • "0" .
  • Choses qui vont à ceux-là.

"0 mais vrai" n'est pas un de ceux-là, donc ce n'est pas faux.

De plus, Perl renvoie "0 mais vrai" où un nombre est attendu afin de signaler qu'une fonction a réussi même si elle a renvoyé zéro. sysseek est un exemple d'une telle fonction. Étant donné que la valeur doit être utilisée sous forme de nombre, Perl est codé pour le considérer comme un nombre. Par conséquent, aucun avertissement n'est émis lorsqu'il est utilisé en tant que nombre et looks_like_number ("0 mais true") renvoie true.

Autres "vrais zéros" peut être trouvé à http://www.perlmonks.org/?node_id=464548 .

Autre exemple de "0 mais vrai":

Le module DBI utilise " 0E0 " comme valeur de retour pour les requêtes UPDATE ou DELETE n'affectant aucun enregistrement. Il est évalué à true 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.

Je viens de trouver la preuve que la chaîne " 0 mais true " est en fait intégré à l'interprète, comme certaines personnes ici déjà ont répondu:

$ 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

Lorsque vous voulez écrire une fonction qui renvoie soit une valeur entière, soit false ou undef (c'est-à-dire pour le cas d'erreur), vous devez faire attention aux valeur zéro. Le renvoyer est faux et ne devrait pas indiquer la condition d'erreur, donc renvoyer " 0 mais true " rend la valeur de retour de la fonction vraie tout en renvoyant la valeur zéro lorsque le calcul est terminé.

" 0 mais vrai " est une chaîne comme n'importe quelle autre chaîne, mais en raison de la syntaxe de perl, elle peut avoir une fonction utile, à savoir renvoyer un zéro entier à partir d'une fonction sans que le résultat ne soit "faux" (aux yeux de perl).

Et la chaîne n'a pas besoin d'être "0 mais vraie". "0 mais faux" est toujours "vrai" au sens booléen.

considérez:

if(x)

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

Le résultat de tout cela est que vous pouvez avoir:

sub find_x()

et que ce code puisse imprimer "& 0;" " comme sortie:

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

La chaîne `` 0 mais true '' reste 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 "warning"!)

'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. ...
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top