perl - 为什么 "!!"在 Perl 中被认为是错误形式?

标签 perl boolean type-conversion

在最近的一次求职面试过程中,我提交了一些示例 Perl 代码,其中使用了所谓的“ secret ”!! operator 。后来,在讨论代码时,一位面试官问我为什么选择使用它,并表示它被认为是不好的形式。他没有详细说明原因。

我和我的团队多年来一直在使用这个运算符,但从未意识到它被认为是“糟糕的形式”。

“bang bang”运算符是否有副作用或其他意外行为?为什么它被某些人认为是“不好的形式”?有惯用的替代方法吗?

下面是一些我认为!!可接受和/或理想的示例。

  1. 编码练习中的实际代码,这是添加 boolean 值的示例:

    while (my $line = <$F>) {
        # snip
        exists $counts{lines} and $counts{lines} += !! chomp $line;
    }
    
  2. 使用 boolean 值作为哈希键(显然是一个简化的示例):

    sub foo {
        my ($input) = @_;
        my %responses = ( '' => "False", 1 => "True" );
        return $responses{ !! $input };
    }
    
  3. 在按位运算中使用 boolean 值,甚至使用 pack():

    sub foo {
        my ( $a, $b, $c ) = @_;
        my $result = !!$a + (!! $b)<<1 + (!! $c)<<2;
        return $result;
    }
    
  4. 您需要进行类型转换以供外部库/进程使用,例如数据库,它只认为某些值是真实的:

    my $sth = $dbh->prepare("INSERT INTO table (flag,value) VALUES (?,?)")
    $sth->execute("i_haz_cheeseburger", !! $cheeseburger_string)
    

最佳答案

我称其为“糟糕的形式”,因为它根本没有必要。您不需要在 Perl 中进行 boolean 转换。因此,往好了说,它是多余的,往坏了说,它是一种混淆。

虽然你可以在 Perl 中使用一些非常好的技巧,但该语言的最大问题之一(至少在感知上)是它很容易“编写一次”代码。

毕竟 - 当您可以测试标量时,为什么需要“双重否定”标量来获得 boolean 值?

my $state = !! 'some_string';
if ( $state ) { print "It was true\n" };

或者:

if ( 'some_string' ) { print "It was true\n" };

这是真的 - 借助“ secret ”运算符、基于标点符号的变量等,您可以编写一些极其难以理解的 Perl 代码。而且它会工作得很好 - 例如 - 我仍然认为这是一个杰作: 3-D Stereogram, Self replicating source

但这不是“好代码”。对于“现实世界”的使用,您的代码需要清晰、易懂且易于排除故障。

关于替代方案;

while (my $line = <$F>) {
    # snip
    exists $counts{lines} and $counts{lines} += !! chomp $line;
}

这是...计算您成功chomp一行的频率(我想)?所以基本上它只是计算输入中的行数。

为此,我会考虑“使用 $.”。除非我错过了关于你的代码的一些深刻的东西?

"What if it's not chomp?"

嗯,好的。怎么样:

 $counts{lines}++ if foo();

为此:

sub foo {
    my ($input) = @_;
    my %responses = ( "" => "False", 1 => "True" );
    return $responses{ !! $input };
}

我会把它写成:

sub foo {
    my ($input) = @_;
    return $input ? "True" : "False";
}

对于最后一个条件 - 将标志打包到一个字节中:

sub flags {
    my @boolean_flags = @_;
    my $flags = 0;
    for ( @boolean_flags ) {
        $flags<<=1;
        $flags++ if $_;
    }
    return $flags;
}

print flags ( 1, 1, 1 );

或者,如果您正在做类似的事情 - 借鉴如何 Fcntl通过定义要根据位置添加的值来实现这一点,因此您不必担心位置参数问题:

You can request that the flock() constants (LOCK_SH, LOCK_EX, LOCK_NB and LOCK_UN) be provided by using the tag :flock.

然后你可以:

flock ( $fh, LOCK_EX | LOCK_NB );

它们是按位定义的,因此它们通过 or 运算符“添加” - 但这意味着它是幂等操作,而设置 LOCK_NB 两次则不会。

例如,

 LOCK_UN = 8
 LOCK_NB = 4
 LOCK_EX = 2
 LOCK_SH = 1

如果我们将问题扩展到不太主观的问题:

I'm asking for the reasons to avoid !!

  • Perl 评估变量的“真实性”,因此实际上并不需要实际的逻辑 boolean 值。
  • 条件语句比相应的 boolean 代数更清晰。 if ( $somecondition ) { $result++ }$result += 更清楚! $一些条件
  • 它位于 secret 运算符(operator)名单上因为它是晦涩难懂的。您 future 的维护程序员可能不会意识到这一点。
  • !!11!!0dualvar('', 0)。虽然这非常灵活,但它可能会令人惊讶,特别是因为大多数人甚至不知道双变量是什么,更不用说 ! 返回一个。如果您使用三元,那么您将得到明确的值:$value ? 1:0

关于perl - 为什么 "!!"在 Perl 中被认为是错误形式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33014080/

相关文章:

java - boolean 值不能同时工作

c# - 转换为字符串时删除无关紧要的小数位 (C#)

python - 如何将二维数组转换为 python 3 中的元组?

regex - Perl: “Quantifier in {,} bigger than 32766 in regex”

html - perl 不在命令提示符下打印特殊字符

perl - 如何确定 Perl 模块是否是跨平台的?

Java减少对象的大小

c++ - 在 C++ 中,使用 bool 而不是 char 有什么意义?

Qt - 将 QDateTime 转换为 QJSValue

regex - Perl/regex删除字符串的前3行和后3行