web-dev-qa-db-ja.com

Perlで「0 but true」とはどういう意味ですか?

誰かが文字列「0 but true」がPerlで正確に何を意味するか説明できますか?私が理解している限り、整数の比較ではゼロに等しくなりますが、ブール値として使用するとtrueと評価されます。これは正しいです?これは言語の通常の動作ですか、それともインタープリターで特別なケースとして扱われる特別な文字列ですか?

61
jkramer

これは言語の正常な動作です。 perlsyn マンページの引用:

数値0、文字列'0'および""、空のリスト()undefは、ブールコンテキストではすべてfalseです。他のすべての値は真です。 !またはnotによる真の値の否定は、特別な偽の値を返します。文字列として評価される場合、""として扱われますが、数値としては0として扱われます。

このため、0を(成功した)戻り値として返すことを期待するシステムコールから0を返す方法が必要であり、実際に偽の値。 "0 but true"はその目的を果たします。

57

それはそれを数値として扱うためにPerlコアでハードコードされているからです。これは、Perlの規則とioctlの規則を一緒に機能させるためのハックです。 perldoc -f ioctlから:

ioctl(およびfcntl)の戻り値は次のとおりです。

if OS returns:      then Perl returns:

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

したがって、Perlは成功するとtrueを返し、失敗するとfalseを返しますが、オペレーティングシステムによって返される実際の値は簡単に判断できます。

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

特別な文字列"0 but true"は、不適切な数値変換に関する-wの苦情から免除されます。

52
geekosaur

他の人が言ったことに加えて、"0 but true"は、数値コンテキストで警告しないという点で特殊なケースです。

$ 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

0 but trueは、Perlの特殊なケースです。あなたの単なる人間の目には、それは数のようには見えませんが、賢明であり、Perlがそれが本当に数であることを理解しているすべてのことを知っています。

これは、Perlサブルーチンが0の値を返したときに、ルーチンが失敗したか、falseの値を返したと見なされるという事実に関係しています。

2つの数値の合計を返すサブルーチンがあるとします。

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

サブルーチンが1を返すため、最初のステートメントは無効になりません。それは良い。サブルーチンはcowdogに追加できないため、2番目のステートメントは終了します。

そして、3番目のステートメント?

うーん、3-3に追加できます。 0を取得するだけですが、addサブルーチンが機能しても、プログラムが停止します。

これを回避するために、Perlは0 but trueを数値と見なします。私のaddサブルーチンがだけでなく0もtrueを返す場合、私の3番目のステートメントは機能します。

しかし、0ですがtrueは数値ゼロですか?これらを試してください:

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

うん、ゼロだ!

index サブルーチンは非常に古いPerlの一部であり、0の概念の前に存在していましたが、trueがありました。文字列にある部分文字列の位置を返すと仮定します。

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

最後の文は-1を返します。つまり、私がこれをした場合:

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

通常は標準関数を使用するので、機能しません。 2番目のステートメントで行ったように「barfoo」と「bar」を使用すると、else句が実行されますが、3番目のように「barfoo」と「fu」を使用すると、if句が実行されます。私が欲しいものではありません。

ただし、indexサブルーチンが2番目のステートメントで0だがtrueを返し、3番目のステートメントでundefを返した場合、my if/else句は機能しました。

32
David W.

また、文字列 "Perlコードで使用される" 0E0 " が表示される場合もありますが、これは同じことを意味します。0E0は指数表記で書かれた0を意味します。ただし、Perlは「0」、「」、またはundefのみをfalseと見なすため、ブール値のコンテキストではtrueと評価されます。

24
Andy Lester

これは、Perlのソースコード、具体的には Perl_grok_number_flags in numeric.c にハードコードされています。

そのコードを読んで、文字列 "infinity"(大文字と小文字を区別しない)がlooks_like_numberテストにも合格することを発見しました。私はそれを知りませんでした。

12
Simon Whitaker

整数のコンテキストでは、0(文字列の先頭の数値部分)と評価され、ゼロになります。スカラーコンテキストでは、それは空ではない値なので、trueです。

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

    (出力なし)

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

    (本当の印刷)

10
Daniel Papasian

は、Perl(およびCに関連する他の言語)ではfalseを意味します。ほとんどの場合、これは妥当な動作です。他の言語(Luaなど)はをtrueとして扱い、true以外の値を表す別のトークン(多くの場合nilまたはfalse)を提供します。

Perlの方法がうまく機能しない1つのケースは、数値を返すか、関数が何らかの理由で失敗した場合にfalse値を返す場合です。たとえば、ファイルから1行を読み取り、その行の文字数を返す関数を記述したとします。関数の一般的な使用法は次のようになります。

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

特定の行の文字数が0の場合、whileループはファイルの終わりの前に終わります。したがって、characters_in_line関数は、特殊文字の0文字で、代わりに'0 but true'を返す必要があります。そうすれば、関数はwhileループで意図したとおりに機能しますが、数値として使用した場合は正しい答えも返します。

これは言語の組み込み部分ではないことに注意してください。むしろ、文字列を数値として解釈するPerlの機能を利用しています。そのため、代わりに他の文字列が使用されることがあります。 [〜#〜] dbi [〜#〜]は、たとえば"0E0"を使用します。数値コンテキストで評価すると、を返しますが、ブールコンテキストではfalseを返します。

9
Jon Ericson

間違っていること:

  • _""_。
  • _"0"_。
  • それらを文字列化するもの。

_"0 but true"_はそれらの1つではないため、偽ではありません。

さらに、Perlは_"0 but true"_を返します。ここでは、ゼロが返されても、関数が成功したことを示すために数値が必要です。 sysseek は、このような関数の例です。値は数値として使用されることが想定されているため、Perlは数値と見なすようにコーディングされています。その結果、数値として使用しても警告は発行されず、looks_like_number("0 but true")はtrueを返します。

その他の「真のゼロ」は http://www.perlmonks.org/?node_id=464548 にあります。

6
ikegami

「0 but true」という文字列が実際にインタプリタに組み込まれているという証拠を見つけました。

$ 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
4
jkramer

"0 but true"の別の例:

DBIモジュールは、レコードに影響を与えなかったUPDATEまたはDELETEクエリの戻り値として「0E0」を使用します。ブールコンテキスト(クエリが適切に実行されたことを示す)ではtrueに評価され、クエリによって変更されたレコードがないことを示す数値コンテキストでは0に評価されます。

4
kixx

整数値、またはfalseを返す関数を記述したい場合 未定義 (つまり、エラーの場合)次に、値0に注意する必要があります。戻り値はfalseであり、エラー状態を示すものではないため、「0 but true」を返すと、関数の戻り値がtrueになり、計算が行われたときに値0が返されます。

3
andy

"0 but true"は他の文字列と同じですが、Perlの構文により、関数から整数ゼロを返し、結果が "false"にならない(Perlの観点から)ことができます。

また、文字列は「0でなくtrue」である必要はありません。 "0 but false"はブール値の意味ではまだ "true"です。

検討してください:

if(x)

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

これらすべての結果は、次のことが可能です。

sub find_x()

そして、このコードがその出力として「0」を出力できるようにしてください:

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

文字列 `` 0 but true ''はまだ特別なケースです:

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

以下を与える:(「警告」に注意!)

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

...そして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