Perl 中的“0 但为真”是啥意思?

Posted

技术标签:

【中文标题】Perl 中的“0 但为真”是啥意思?【英文标题】:What does "0 but true" mean in Perl?Perl 中的“0 但为真”是什么意思? 【发布时间】:2010-09-12 21:32:07 【问题描述】:

谁能解释一下字符串“0 but true”在 Perl 中的确切含义?据我了解,它在整数比较中等于零,但在用作布尔值时计算为真。它是否正确?这是语言的正常行为,还是在解释器中被视为特殊情况的特殊字符串?

【问题讨论】:

字符串"0E0" 另一个类似于"0 but true"。它不是硬编码,而是 Perl 指数符号的结果。作为一个非空、非零字符串,它是真的。作为一个数字,它是 0。DBI 使用它作为来自 execute 之类的返回值,表示 SQL 语句有效,但没有行受到影响。 我理解转换为数字时警告特殊处理“0但为真”的原因,但我仍然认为look_like_number 应该返回false。 【参考方案1】:

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

if (int("0 but true")) print "zero";

(无输出)

if ("0 but true") print "true";

(打印为真)

【讨论】:

【参考方案2】:

当你想编写一个返回整数值或 falseundef 的函数(即对于错误情况),那么你必须注意值为零。返回它是 false 并且不应指示错误情况,因此返回“0 但为真”使函数返回值为真,同时在对其进行数学运算时仍将值零传回。

【讨论】:

【参考方案3】:

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

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

因此,需要有一种方法从系统调用中返回 0,该系统调用期望将 0 作为(成功的)返回值返回,并留下一种通过实际返回假值。 "0 but true" 就是为了这个目的。

【讨论】:

Nit: '0 but true' 不仅仅适用于系统调用。 一些模块使用字符串“0E0”,它作为数字计算为0,但作为布尔值计算为真。 OMG Perl 太模棱两可了 :O @Andrei:这不是模棱两可的;很清楚。您可能会感到困惑,但这是完全不同的。 "0 but true" 是特殊的。当你使用它时它不会产生一些警告:perl -wle'print 0+"0 but false"' 打印“Argument "0 but false" is not numeric in addition (+) at -e line 1.",但 perl -wle'print 0+"0 but true"' 不会。【参考方案4】:

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

【讨论】:

【参考方案5】:

"0 but true" 和其他字符串一样,但由于 perl 的语法,它可以提供有用的目的,即从函数返回整数零而不结果为 "false"(在 perl 眼中)。

而且字符串不必是“0 但为真”。 “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";

【讨论】:

你确定那个裸词是假的吗?这不是我做 $ perl -wle 'print "true\n" if false;' 时得到的 MarkHu,你说得对,perl 中没有真假关键字。我已经编辑了原始答案。【参考方案6】:

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

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

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

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

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

【讨论】:

在语言中预编程的 0 是 true 还是 false 的默认值?我不明白为什么有人会希望它在不同语言之间有所不同。 在大多数语言中不是 0 false 和 1 true 吗?【参考方案7】:

您可能还会看到字符串"0E0" used in Perl code,它的含义相同,其中0E0 仅表示用指数表示法书写的0。但是,由于 Perl 只将 "0"、'' 或 undef 视为 false,因此它在布尔上下文中的计算结果为 true。

【讨论】:

【参考方案8】:

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

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

【讨论】:

【参考方案9】:

我刚刚发现了字符串“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

【讨论】:

【参考方案10】:

虚假的东西:

"""0"。 将这些东西串起来。

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

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

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

【讨论】:

但这并不能解释为什么looks_like_number( "0 but true" ) 为真,而looks_like_number( "0 but foobar" ) 为假。 @friedo,Perl 不会将“0 但 foobar”作为数字返回。 @friedo,您实际上是在问为什么 Perl 需要返回零值但计算结果为 true 的值?这样您就可以轻松地评估当零是可能的返回值时函数是否成功。 sysseek 就是一个例子。 不,我在问为什么0 but true 看起来像一个数字,而0 but anything else 却不是。在数字上下文中,它们都将评估为 0。我知道0 but true 是干什么用的。 @friedo,为什么“0 but nothing else”、“123abc”、“foo bar”等是数字?【参考方案11】:

因为它在 Perl 核心中被硬编码为将其视为数字。这是使 Perl 的约定和 ioctl 的约定一起发挥作用的 hack;来自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 投诉 关于不正确的数字转换。

【讨论】:

也被 msgctl、semctl、sysseek 和各种 CPAN 模块使用。 “将其视为数字”具有误导性; “0 xxx”、“foo”或“123profit”在数字上下文中也被视为数字; “0 but true”的特别之处在于它故意不会引起警告。 你会发现像 relops 这样的东西返回的特殊定义的空字符串也是一个有效的数字:perl -wle 'printf "%d\n", 4 > 5' 产生 0 sans 投诉。 FWIW:Perl DBI 模块使用 '0E0' 作为 '0 but true' 的变体。 这并不是真正的变体,它只是以指数格式表示的 0。【参考方案12】:

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

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

【讨论】:

一些 C 库使用“Infinity”(或“+Infinity”或“-Infinity”)作为浮点无穷大的字符串化,而不是“Inf”的变体。【参考方案13】:

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 视为一个数字。如果我的 add 子例程不仅返回 0,而且返回 0 而是 true,那么我的第三条语句将起作用。

但是 0 but 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 但真正 的概念出现之前就已经存在。假设返回位于字符串中的子字符串的位置:

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 but true 对于第二个语句和 undef 对于第三个语句,我的 if/else 子句会起作用。 p>

【讨论】:

【参考方案14】:

字符串 ``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. ...

【讨论】:

以上是关于Perl 中的“0 但为真”是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章

perl 解释器的状态码是啥意思?

jmeter中的正则表达式是啥意思

shell中,awk命令的$0是啥意思?

从 Perl 中的文本文件读取时跳过标题的最佳方法是啥?

从 Perl 中的哈希中获取具有最高值的键的最简单方法是啥?

ASP、PHP、CGI、jsP C语言、C++、VB、JAVA、PERL、DELPHI YSQL、SQL、FOXPRO WIN2K、WINNT 是啥意思啊