【问题标题】:Why is '0' false in Perl?为什么 Perl 中的“0”为假?
【发布时间】:2013-01-10 00:06:03
【问题描述】:

首先,我来自 C、Java、Python 背景。最近,我开始为我的新工作学习 Perl,我对 '0' (0-string) 是假的感到好奇。

我了解到这种特殊行为是 Perl 必须使用 <> 操作符来读取文件的原因,所以对我来说,这更像是一个设计缺陷,而不是现在的任何事情。但是,我也知道 Perl 是一种成熟的语言,我猜这种行为有其用途,否则它早就被修复了。

那么'0' = false 在什么情况下有用?

【问题讨论】:

  • 语言不像应用程序。一旦字符串“0”的虚假性被确定,它不能被改变而不会有破坏无数功能程序的风险。
  • 还有“0但假”的把戏。

标签: perl


【解决方案1】:

如果您读到它与<> 有任何关系,那么您正在阅读不良来源;我无法想象这种说法会从何而来。

'0' 是假的,因为几乎所有地方 perl 都不区分以数字形式存储的数字和以字符串形式存储的数字;在布尔测试中这样做会违反这种规定。

在 '0' 为真的语言(Python、Javascript?)中,我觉得奇怪的是 '' 为假;为什么要为一个字符串而不是另一个字符串例外?

【讨论】:

  • 我认为 OP 正在谈论 while (<>) { ... } 中的隐式 defined 测试。这样当您从<> 读取时,循环不会在读取字符串为'0' 时结束。尝试perl -MO=Deparse -E 'while (<>) { say }' 明确查看。
  • @JoelBerger: 注意while (<>) 将设置$_"0" 仅当输入的最后一行只包含字符0 没有终止换行符我>。否则,单独一行上的0 会将$_ 设置为"0\n"。这是一个奇怪的极端情况,但如果 while (<>) 没有正确处理它会很尴尬。
  • 这更像是一个特殊的while而不是<>;注意这里也适用:while ( glob "{0,1}" ) 和这里:for (File::Temp->newdir) { mkdir "$_/0"; opendir DH, $_; say while readdir *DH }
【解决方案2】:

Perl 没有显式类型,它对类型的解释高度依赖于上下文。例如:

$a = "2b";
$b = "3a";
$c = $a + $b;
print $c;

产量为 5。

另一方面...

$a = "b2";
$b = "3a";
$c = $a + $b;
print $c;

产量 3.

还有……

$a = "b2";
$b = "3a";
$c = $a.$b;
print $c;

产量 b23a

所以“'0'(字符串)”不是字符串、数字或布尔值,直到你使用它,然后它可以是任何这些东西,由它的用途决定。直到您尝试操作才确定类型。然后 Perl 评估上下文以努力实现您的意图并采取相应的行动。这是一个特性,以及为什么在 Perl 中有很多方法可以做事。它当然会导致大量令人困惑的代码,但非常适合 1-liner、混淆和 Perl 高尔夫。

【讨论】:

    【解决方案3】:

    Perl steals 继承了许多其他语言的特性,包括 C、awk、Bourne shell 和许多其他语言。

    在 C 中,任何 0 值都是假的,任何非零值都是真。 Perl 只是使用相同的语义。

    Perl 比 C 有更多可以在标量或布尔上下文中使用的东西,尤其是字符串,这一事实意味着 Perl 有 多个 错误值。

    将整数 0 设为 false 对 C 程序员来说非常有意义。将空字符串 "" 设为 false 也很有意义。由于 Perl 可以将相同的标量视为数字或字符串,因此将字符串 "0" 设为 false 几乎是不可避免的。

    例如:

    $x = 2;
    $x -= 2;
    print "x = $x\n"; # prints "x = 0"
    if ($x) {
        print "A C programmer would be surprised to see this\n";
    }
    
    $x = "";
    $x .= chr(48);
    # Now $x eq "0", a string value that was built without reference to
    # the number zero -- but it's nearly the same thing as the number 0.
    print "\$x = $x\n"; # pritn "x = 0"
    if ($x) {
        print "A C programmer would be equally surprised to see this\n";
    }
    

    如果 Perl 是从零开始设计的,没有从其他语言中借用这么多特性,那么它可能会在字符串和数字之间做出更明确的区分,而不是将它们作为标量组合在一起。给定这样一种假设的类 Perl 语言,空字符串和数字 0 很可能为假,但字符串 "0" 为真——您需要显式转换才能从数字 @987654327 转换@ 到字符串"0"

    但是 Perl 就是这样。

    【讨论】:

      【解决方案4】:

      理想情况下,内部存储格式在 Perl 中永远不会重要。零就是零,不管是存储在IV、UV、NV、PV等中。

      事实上,因为它可以,Perl 会改变值的存储格式,这可能会让您感到惊讶。如果字符串0 为真,则以下将打印“真”:

      $x = 0;
      print("$x\n");
      if ($x) {
         print("true\n");
      } else {
         print("false\n");
      }
      

      【讨论】:

        【解决方案5】:

        Perl 有许多被认为是“假”的值:undef、零、字符串"0"、空字符串、一个特殊的布尔值,它根据上下文变化为空字符串或空列表,以及为布尔上下文重载的对象。

        其中大部分(undef、零、空字符串、特殊值、对象)实际上非常有用。字符串"0" 为假源于 perl 实现标量和假性的方式:标量包含字符串部分和数字部分。为了确定一个值是否为假,首先查询字符串部分。为什么需要这样做?

        my $false_ish = 0;  # the scalar contains only a number
        '' . $false_ish;    # force stringy context. the scalar now contains stringy portion.
        if ($false_ish) { ... } # string portion is consulted first...
        

        没有这个,一旦你在需要字符串的地方使用数字零,它就会失去它的虚假性。另一方面,这允许"0 but true",一个真正的字符串,它是数字零,和"0E0",它是零的科学记数法,但也可以评估为真。

        【讨论】:

          【解决方案6】:

          0 在 C 中也等同于 false - 在几种“传统”编程语言中等同于 false,这可能是由于 0 与二进制和电路的内在联系,其中 0 可能表示“不收费”。

          无论如何,较新的语言通常会继承以前语言的行为和解释。 0 是“不收费”或“有收费是假的”的二进制含义早已从任何高级编程语言中抽象出来,但即使通过最现代的编程语言,语义的花絮仍然存在。

          另外 - 据我所知,它与 无关 - 你在哪里读到的?

          【讨论】:

          • 我认为这不是重点。 GoldenD 专门讨论了字符串“0”,以及为什么 Perl 以与整数 0 相同的方式解释它。HeWas 在上面对此进行了评论。将相同的操作与另一种语言进行比较。在 Python 中:“0”== True 计算结果为 False。
          猜你喜欢
          • 2018-05-01
          • 2021-06-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-25
          • 1970-01-01
          相关资源
          最近更新 更多