誰かが文字列「0 but true」が Perl で正確に何を意味するのか説明できますか? 私が理解している限り、整数比較ではゼロに等しくなりますが、ブール値として使用すると true に評価されます。これは正しいです?これは言語の通常の動作ですか、それともインタープリターで特別なケースとして扱われる特別な文字列ですか?
14 に答える
それは言語の正常な動作です。マンページを引用perlsyn
:
数値
0
、文字列'0'
および""
、空のリスト()
、およびundef
は、ブール値のコンテキストではすべて false です。他のすべての値は true です。!
またはによる true 値の否定はnot
、特別な false 値を返します。文字列として評価すると として扱われます""
が、数値として評価すると として扱われ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 値を返す場合、ルーチンが失敗したか、偽の値を返したと見なされるという事実に関係しています。
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
これを回避するために、Perl0 but true
は数値であると見なします。addサブルーチンが単に0ではなく0 ではなく trueを返す場合、3 番目のステートメントは機能します。
しかし、 0は数値の 0 ですが、真ですか? これらを試してください:
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...
最後のステートメントは a を返します-1
。つまり、これを行った場合:
if ($position = index($string, $substring)) {
print "It worked!\n";
}
else {
print "If failed!\n";
}
私が通常標準関数で行うように、それは機能しません。2 番目のステートメントのように "barfoo" と "bar"を使用すると、句が実行されますelse
が、3 番目のように "barfoo" と "fu" を使用すると、if
句が実行されます。私が欲しいものではありません。
ただし、index
サブルーチンが 0 を返し、2 番目のステートメントと3 番目のステートメントでtrueを返す場合、 /句は機能します。undef
if
else
Perl コードで使用される文字列"0E0"も表示される場合がありますが、これは同じことを意味します。0E0 は、指数表記で書かれた 0 を意味します。ただし、Perl は "0"、''、または undef のみを false と見なすため、ブール値のコンテキストでは true と評価されます。
これは、Perl のソース コード、特にnumeric.c の Perl_grok_number_flags にハードコーディングされています。
そのコードを読んで、文字列 "infinity" (大文字と小文字を区別しない) も、looks_like_number テストに合格することがわかりました。私はそれを知りませんでした。
整数コンテキストでは、0 (文字列の先頭にある数値部分) と評価され、ゼロになります。スカラー コンテキストでは、これは空でない値であるため、true です。
if (int("0 but true")) { print "zero"; }
(出力なし)
if ("0 but true") { print "true"; }
(印刷 true)
0は、Perl (および C に関連する他の言語) では false を意味します。ほとんどの場合、これは合理的な動作です。他の言語 (Lua など) は0を true として扱い、別のトークン (多くの場合nilまたはfalse ) を提供して true でない値を表します。
Perl の方法がうまく機能しないケースの 1 つは、数値を返したい場合、または何らかの理由で関数が失敗した場合に偽の値を返したい場合です。たとえば、ファイルから行を読み取り、その行の文字数を返す関数を作成するとします。関数の一般的な使用法は、次のようなものです。
while($c = characters_in_line($file)){
...
};
特定の行の文字数が 0 の場合、whileループはファイルが終了する前に終了することに注意してください。したがって、characters_in_line関数は 0 の文字を特別に扱い、代わりに'0 but true'を返す必要があります。そうすれば、関数はwhileループで意図したとおりに機能しますが、数値として使用された場合は正しい答えも返します。
これは言語の組み込み部分ではないことに注意してください。むしろ、文字列を数値として解釈する Perl の機能を利用しています。そのため、代わりに他の刺し傷が使用されることがあります。 たとえば、 DBIは"0E0"を使用します。数値コンテキストで評価すると0が返されますが、ブール値コンテキストでは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 でも真」の別の例:
DBI モジュールは、どのレコードにも影響を与えなかった UPDATE または DELETE クエリの戻り値として "0E0" を使用します。ブール コンテキストでは true (クエリが適切に実行されたことを示す) と評価され、数値コンテキストでは 0 と評価され、クエリによってレコードが変更されなかったことを示します。
「0buttrue」は他の文字列と同じですが、perlの構文により、結果が「false」になることなく関数から整数ゼロを返すという便利な目的を果たすことができます(perlの目には)。
また、文字列は「0がtrue」である必要はありません。「0butfalse」は、ブール値の意味で「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";
}
整数値、またはfalseまたはundef (つまりエラーの場合) を返す関数を書きたい場合は、値ゼロに注意する必要があります。それを返すことは false であり、エラー状態を示すべきではないため、「0 but true」を返すと、関数の戻り値は true になりますが、計算が完了すると値ゼロが返されます。
文字列「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. ...