在Perl中,“0但是真实”是什么意思?

时间:2008-09-24 21:00:46

标签: perl integer boolean

有人可以解释Perl中字符串“0但是true”究竟是什么意思吗?据我所知,它在整数比较中等于零,但在用作布尔值时求值为true。它是否正确?这是语言的正常行为,还是在解释器中作为特殊情况处理的特殊字符串?

14 个答案:

答案 0 :(得分:56)

这是语言的正常行为。引用perlsyn联机帮助页:

  

号码0,字符串'0'"",空列表()undef   在布尔上下文中都是false。所有其他值都是真的。否定   !not的真值返回特殊的假值。   当评估为字符串时,它被视为"",但作为数字,它是。{   视为0

因此,需要有一种方法可以从期望返回0的系统调用中返回0作为(成功的)返回值,并留下一种方法来表示失败的情况实际上返回一个假值。 "0 but true"就是为了这个目的。

答案 1 :(得分:51)

因为它在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投诉   关于不正确的数字转换。

答案 2 :(得分:45)

除了其他人所说的,"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

答案 3 :(得分:32)

0 but true是Perl中的一个特例。虽然对于你的凡人来说,它看起来并不像一个数字,明智而且所有人都知道Perl知道它确实是一个数字。

这与Perl子例程返回0值的事实有关,假设例程失败或返回错误值。

想象一下,我有一个子程序,它返回两个数字的总和:

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

并且,第三个声明?

嗯,我可以将3添加到-3。我得到0,但即使add子程序有效,我的程序也会死!

为了解决这个问题,Perl认为0 but true是一个数字。如果我的添加子例程不仅返回 0 ,而且 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的概念之前存在但是真正的存在。假设返回位于字符串中的子字符串的位置:

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

正如我通常使用标准功能一样,它不起作用。如果我像在第二个语句中那样使用“barfoo”和“bar”,else子句会执行,但如果我在第三个中使用“barfoo”和“fu”,那么if子句将执行。不是我想要的。

但是,如果index子例程为第二个语句返回 0但是返回true ,而对于第三个语句返回undef,我的if / {{1} }子句会起作用。

答案 4 :(得分:24)

您可能还会看到字符串"0E0" used in Perl code,这意味着相同的事情,其中​​0E0仅表示以指数表示法写入的0。但是,由于Perl只将“0”,“或undef视为false,因此在布尔上下文中计算结果为true。

答案 5 :(得分:12)

它在Perl的源代码中是硬编码的,特别是在Perl_grok_number_flags in numeric.c中。

读取该代码我发现字符串“infinity”(不区分大小写)也通过了looks_like_number测试。我不知道。

答案 6 :(得分:10)

在整数上下文中,它的计算结果为0(字符串开头的数字部分),为零。在标量上下文中,它是一个非空值,所以它是真的。

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

    (无输出)

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

    (打印为真)

答案 7 :(得分:9)

0 在Perl(以及与C相关的其他语言)中表示false。在大多数情况下,这是一种合理的行为。其他语言(例如Lua)将 0 视为true,并提供另一个令牌(通常为 nil false )来表示非真值。

Perl方式不能很好地工作的一种情况是当你想要返回一个数字时,或者如果函数由于某种原因失败,则返回false值。例如,如果您编写的函数从文件中读取一行并返回该行上的字符数。该函数的常见用法可能是:

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

请注意,如果特定行上的字符数为0, while 循环将在文件结束之前结束。因此 characters_in_line 函数应该是特殊情况0字符并返回'0而不是true'。这样,该函数将在 while 循环中按预期工作,但如果将其用作数字,也会返回正确的答案。

请注意,这不是语言的内置部分。相反,它利用了Perl将字符串解释为数字的能力。因此有时会使用其他刺痛。例如, DBI 使用“0E0”。在数值上下文中进行评估时,它们返回 0 ,但在布尔上下文中, false

答案 8 :(得分:6)

虚假的事情:

  • ""
  • "0"
  • 与那些串联的东西。

"0 but true"不是其中之一,所以这不是假的。

此外,Perl返回"0 but true",其中包含一个数字,以便发信号表示函数成功,即使它返回零。 sysseek就是这种功能的一个例子。由于该值预计将用作数字,因此Perl被编码为将其视为数字。因此,当它用作数字时不会发出警告,并且looks_like_number("0 but true")返回true。

其他“真正的零”可以在http://www.perlmonks.org/?node_id=464548找到。

答案 9 :(得分:4)

“0但是真实”的另一个例子:

DBI模块使用“0E0”作为不影响任何记录的UPDATE或DELETE查询的返回值。它在布尔上下文中计算为true(表示查询已正确执行),在数字上下文中为0,表示查询未更改任何记录。

答案 10 :(得分:4)

我刚刚发现证明字符串“0但是真的”实际上已经内置到解释器中,就像有些人已经回答:

$ 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

答案 11 :(得分:3)

如果要编写一个返回整数值的函数,或者 false undef (即错误情况),那么你必须注意价值零。返回它是错误的并且不应该指示错误条件,因此返回“0但是true”使函数返回值为true,同时在数学完成时仍然返回值零。

答案 12 :(得分:3)

“0但是true”是一个字符串,就像任何其他字符串一样,但由于perl的语法,它可以起到一个有用的作用,即从函数返回整数零而结果不是“假”(在perl眼中)。

字符串不必是“0但是为真”。 “0但是假”在布尔意义上仍然是“真实的”。

考虑:

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

答案 13 :(得分:2)

字符串“0但是真的”仍然是一个特例:

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. ...