誰かが文字列「0 but true」がPerlで正確に何を意味するか説明できますか?私が理解している限り、整数の比較ではゼロに等しくなりますが、ブール値として使用するとtrueと評価されます。これは正しいです?これは言語の通常の動作ですか、それともインタープリターで特別なケースとして扱われる特別な文字列ですか?
これは言語の正常な動作です。 perlsyn
マンページの引用:
数値
0
、文字列'0'
および""
、空のリスト()
、undef
は、ブールコンテキストではすべてfalseです。他のすべての値は真です。!
またはnot
による真の値の否定は、特別な偽の値を返します。文字列として評価される場合、""
として扱われますが、数値としては0
として扱われます。
このため、0
を(成功した)戻り値として返すことを期待するシステムコールから0
を返す方法が必要であり、実際に偽の値。 "0 but true"
はその目的を果たします。
それはそれを数値として扱うために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
の苦情から免除されます。
他の人が言ったことに加えて、"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
値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
を返すため、最初のステートメントは無効になりません。それは良い。サブルーチンはcowをdogに追加できないため、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
句は機能しました。
また、文字列 "Perlコードで使用される" 0E0 " が表示される場合もありますが、これは同じことを意味します。0E0は指数表記で書かれた0を意味します。ただし、Perlは「0」、「」、またはundefのみをfalseと見なすため、ブール値のコンテキストではtrueと評価されます。
これは、Perlのソースコード、具体的には Perl_grok_number_flags in numeric.c にハードコードされています。
そのコードを読んで、文字列 "infinity"(大文字と小文字を区別しない)がlooks_like_numberテストにも合格することを発見しました。私はそれを知りませんでした。
整数のコンテキストでは、0(文字列の先頭の数値部分)と評価され、ゼロになります。スカラーコンテキストでは、それは空ではない値なので、trueです。
if (int("0 but true")) { print "zero"; }
(出力なし)
if ("0 but true") { print "true"; }
(本当の印刷)
は、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を返します。
間違っていること:
""
_。"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 にあります。
「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
"0 but true"の別の例:
DBIモジュールは、レコードに影響を与えなかったUPDATEまたはDELETEクエリの戻り値として「0E0」を使用します。ブールコンテキスト(クエリが適切に実行されたことを示す)ではtrueに評価され、クエリによって変更されたレコードがないことを示す数値コンテキストでは0に評価されます。
整数値、またはfalseを返す関数を記述したい場合 未定義 (つまり、エラーの場合)次に、値0に注意する必要があります。戻り値はfalseであり、エラー状態を示すものではないため、「0 but true」を返すと、関数の戻り値がtrueになり、計算が行われたときに値0が返されます。
"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";
}
文字列 `` 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. ...