60 votes

Que signifie "0 mais vrai" en Perl ?

Quelqu'un peut-il expliquer ce que signifie exactement la chaîne "0 mais vrai" en Perl ? D'après ce que je comprends, elle est égale à zéro dans une comparaison d'entiers, mais évalue à vrai lorsqu'elle est utilisée comme booléen. Est-ce correct ? S'agit-il d'un comportement normal du langage ou d'une chaîne spéciale traitée comme un cas particulier dans l'interpréteur ?

57voto

Chris Jester-Young Points 102876

C'est un comportement normal de la langue. En citant le perlsyn page de manuel :

Le nombre 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 "not" renvoie une valeur fausse spéciale. Lorsqu'elle est évaluée en tant que chaîne, elle est traitée comme '', mais en tant que nombre, elle est traité comme 0.

Pour cette raison, il doit y avoir un moyen de renvoyer 0 à partir d'un appel système qui s'attend à renvoyer 0 comme valeur de retour (réussie), et laisser un moyen de signaler un cas d'échec en renvoyant réellement une valeur fausse. "0 but true" sert cet objectif.

52voto

geekosaur Points 26170

Parce qu'il est codé en dur dans le noyau Perl pour le traiter comme un nombre. Il s'agit d'un hack pour rendre les conventions de Perl et les ioctl Les conventions de l'UE jouent ensemble ; de perldoc -f ioctl :

La valeur de retour de ioctl (y fcntl ) est le suivant :

if OS returns:      then Perl returns:

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

Ainsi, Perl renvoie vrai en cas de succès et faux en cas d'échec, mais vous pouvez pourtant, vous pouvez facilement déterminer la valeur réelle retourné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ée de -w plaintes concernant des conversions numériques incorrectes.

45voto

moritz Points 6295

En plus de ce que les autres ont dit, "0 but true" est un cas particulier en ce sens qu'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

32voto

David W. Points 49436

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

Cela est dû au fait que lorsqu'une sous-routine Perl renvoie une valeur 0, on suppose que la routine a échoué ou a renvoyé une valeur fausse.

Imaginez que j'ai une sous-routine qui renvoie 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 la sous-routine renverra une valeur de 1 . C'est bien. La deuxième instruction mourra parce que la sous-routine ne pourra pas additionner vache a chien .

Et, la troisième déclaration ?

Hmmm, je peux ajouter 3 a -3 . J'ai juste 0 mais mon programme mourra alors, même si l'option add La sous-routine a fonctionné !

Pour contourner ce problème, Perl considère 0 but true pour être un nombre. Si mon ajouter La sous-routine retourne non seulement 0 mais 0 mais vrai ma troisième déclaration fonctionnera.

Mais est-ce que 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";

Oui, c'est zéro !

El indice est un très vieux morceau de Perl et existait avant le concept de 0 mais vrai était dans le coin. Elle est censée 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...

Le dernier statut renvoie un -1 . Ce qui veut dire que si je faisais ça :

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

Comme je le fais habituellement avec les fonctions standard, cela ne fonctionnait pas. Si j'utilisais "barfoo" et "bar" comme je l'ai fait dans la deuxième instruction, la fonction else s'exécuterait, mais si j'utilisais "barfoo" et "fu" comme dans la troisième, la clause if s'exécuterait. Ce n'est pas ce que je veux.

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

24voto

Andy Lester Points 34051

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X