【问题标题】:Why does !1 give me nothing in Perl?为什么 !1 在 Perl 中什么也没给我?
【发布时间】:2010-11-11 05:18:34
【问题描述】:

这很奇怪。 以下:

$sum = !0;
print $sum;

如您所愿打印出 1。但是这个

$sum = !1;
print $sum;

什么也不打印。为什么?

【问题讨论】:

  • 其他人提供了很好的解释,阐明 perl 从根本上将所有内容都视为字符串并根据上下文进行更改。考虑到这一点,你想给 perl 一些上下文,所以下面的方法会起作用:$num = 0; print int( !$num ), "\n"; $num = 1; print int( !$num ), "\n";

标签: perl boolean


【解决方案1】:

请注意:您所写的并不是您认为的那样。请记住,perl 没有真正的布尔数据类型。它有标量、散列、列表和引用。因此,它处理真/假值的方式是上下文相关的。在 perl 中,除了未定义的变量、空列表、空字符串和数字 0 之外,所有内容的计算结果都为“真”。

那么,您的代码正在执行的操作是取一个计算结果为“false”的值的倒数,它可以是上面列表中没有的任何值。按照惯例,为简单起见,perl 返回 1(尽管您不应该依赖它;它可以很好地返回一个包含一系列随机数的列表,因为它也将评估为“真”。)

当您请求求值为“真”的值的倒数时,也会发生类似的情况。实际打印出来的不是“无”,而是空字符串 (''),正如我所提到的,它在布尔表达式中的计算结果为“假”。你可以检查一下:

print "This evaluates to false\n" if( (!1) eq '');

如果您要问为什么 perl 会吐出空字符串而不是其他“假”值之一,那可能是因为 perl 是用来处理字符串的,而这是一个完全合理的字符串。

【讨论】:

  • 有道理,谢谢。我试图在 Perl 中实现一个半加器只是为了好玩,所以我会尝试找到一种解决方法。
  • @aditya 请参阅stackoverflow.com/questions/1134962/… 了解解决方法。
  • 还有一个假值,字符串中只包含一个“0”。
  • 它不仅仅是一个空字符串,它是一个带有 0/'' 的对偶变量。
  • !1 不返回空字符串;它返回一个包含0 和一个空字符串的双变量。例如,perl -wE'say 0+!1; say 0+""' 仅对后一种语句发出警告。
【解决方案2】:

仅返回布尔结果的运算符将始终返回 1 表示 true 和一个特殊的 false 值,即在字符串上下文中为 "" 但在数字上下文中为 0。

【讨论】:

    【解决方案3】:

    这是您已经获得的其他出色答案的附录。

    不是不是不是

    考虑以下测试 Perl 的每个“非”运​​算符的代码:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    for( '!1', 'not 1', '~0' ) {
        my $value = eval;
        my $zero_plus = 0 + $value;
    
        print join "\n", 
            "\nExpression: $_",
            "Value:     '$value'",
            "Defined:   " . defined $value,
            "Length:    " . length($value),
            "Plus:      " . +$value,
            "Plus Zero: '$zero_plus'",
            '';
    }
    
    print "\nTest addition for a literal null string:  ";
    print 0+'', "\n";
    
    use Scalar::Util qw(dualvar);
    
    {   # Test a dualvar 
        my $value = dualvar 0, '';
        my $zero_plus = 0+$value;
    
        print join "\n", 
            "\nExpression: dualvar",
            "Value:     '$value'",
            "Defined:   " . defined $value,
            "Length:    " . length($value),
            "Plus:      " . +$value,
            "Plus Zero: '$zero_plus'",
            '';
    
    }
    

    执行它会导致以下结果。注意警告信息:

    Argument "" isn't numeric in addition (+) at test.pl line 21.
    
    Expression: !1
    Value:     ''
    Defined:   1
    Length:    0
    Plus:
    Plus Zero: '0'
    
    Expression: not 1
    Value:     ''
    Defined:   1
    Length:    0
    Plus:
    Plus Zero: '0'
    
    Expression: ~0
    Value:     '4294967295'
    Defined:   1
    Length:    10
    Plus:      4294967295
    Plus Zero: '4294967295'
    
    Test addition for a literal null string:  0
    
    Expression: dualvar
    Value:     ''
    Defined:   1
    Length:    0
    Plus:
    Plus Zero: '0'
    

    从中我们学到了几件事。

    前两项并不那么令人兴奋:

    • !1not 1 的行为方式基本相同。
    • 不出所料,~1 是不同的(按位不同)。

    现在,有趣的项目:

    • 虽然我们确实收到了第 21 行 (0+'') 的警告,但添加 0+!1 时不会生成警告。

    需要两个人才能纠缠

    发生了一些可疑的事情,这种可疑性与 Perl 中的特殊标量上下文有关。在这种情况下,数字和字符串上下文之间的区别。并且能够创建在每个上下文中具有不同值的变量,也就是对偶变量。

    看起来!1 返回一个对偶变量,该变量在数字上下文中返回 0,在字符串上下文中返回空字符串。

    最后的双变量测试表明自制双变量的工作方式与!1相同。

    但这是件好事

    与许多 Perl 功能一样,对偶变量起初似乎出乎意料,而且可能令人困惑。但是,与其他功能一样,如果使用得当,它们会让生活变得更轻松。

    据我所知,0'' 的对偶变量是唯一在所有标量上下文中将返回 false 的已定义值。所以对于!1 来说这是一个非常明智的返回值。有人可能会争辩说undef 是一个很好的错误结果,但是未初始化的变量无法与错误值区分开来。此外,尝试打印或添加布尔值的结果会受到不必要的警告的困扰。

    另一个著名的双变量是$!$OS_ERROR,如果你是use English。数字形式,你得到错误代码,字符串形式,错误代码为你翻译。

    它不是什么都没有,它是空的,但它没有

    所以总而言之,你没有得到任何东西,你没有得到一个空字符串,你没有得到零。

    你得到一个同时为空字符串和 0 的变量。

    【讨论】:

      【解决方案4】:

      ! 运算符执行布尔运算。 ""(空字符串)就像false0 一样。 1 是一个方便的 true 值。除了产生一些true/false 值之外,不应依赖! 做任何事情。依赖超出此范围的确切值是危险的,并且可能会在 Perl 版本之间发生变化。

      【讨论】:

      • Perl5 版本之间肯定不会改变。
      • 人们会这么认为,但一切皆有可能。此外,我认识一些直到最近还在使用 PHP 4 的人。现在编写的脚本完全有可能持续到 Perl 6,甚至更远。
      • 很少有 perl 5 脚本无需修改就可以在 perl 6 中运行;这是一种不同的语言(虽然仍然是 Perl)
      【解决方案5】:

      perldoc perlsyn:

      真假

      数字 0,字符串 '0' 和 '' , 空列表 () 和 undef 都是 在布尔上下文中为 false。所有其他 价值观是真实的。否定真 价值!或不返回一个特殊的 假值。当评估为 字符串它被视为 '' ,但作为 数,视为0。

      在那里,如果您将值打印为数字,您将得到 0 而不是空字符串:

      printf "%d\n", $_ for map { !$_ } (1, 0);
      

      print 0 + $_, "\n" for map { !$_ } (1, 0);
      

      比较一下

      printf "%s\n", $_ for map { !$_ } (1, 0);
      

      print $_, "\n" for map { !$_ } (1, 0);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-12-09
        • 2021-11-26
        • 2018-05-07
        • 2012-06-07
        • 1970-01-01
        • 2020-01-03
        • 1970-01-01
        相关资源
        最近更新 更多