Fli*_*mzy 58 perl boolean type-conversion
在最近的求职面试过程中,我提交了一些使用所谓的"秘密" !! 操作符的 Perl代码示例.后来,在讨论代码时,其中一位采访者问我为什么选择使用它,并表示它被认为是不好的形式.他没有详细说明原因.
我的团队和我一直使用这个运营商多年,没有意识到它被认为是"糟糕的形式".
"砰砰"操作员是否有副作用或其他意外行为?为什么它或者可能被某些人认为是"糟糕的形式"?有没有惯用的选择?
以下是我认为!!可以接受和/或需要的几个例子.
编码练习中的实际代码,这是添加布尔值的一个例子:
while (my $line = <$F>) {
# snip
exists $counts{lines} and $counts{lines} += !! chomp $line;
}
Run Code Online (Sandbox Code Playgroud)使用布尔值作为散列键(显然是简化示例):
sub foo {
my ($input) = @_;
my %responses = ( '' => "False", 1 => "True" );
return $responses{ !! $input };
}
Run Code Online (Sandbox Code Playgroud)在按位运算中使用布尔值,甚至pack():
sub foo {
my ( $a, $b, $c ) = @_;
my $result = !!$a + (!! $b)<<1 + (!! $c)<<2;
return $result;
}
Run Code Online (Sandbox Code Playgroud)您需要进行类型转换以供外部库/进程使用,例如数据库,它只考虑某些值是真实的:
my $sth = $dbh->prepare("INSERT INTO table (flag,value) VALUES (?,?)")
$sth->execute("i_haz_cheeseburger", !! $cheeseburger_string)
Run Code Online (Sandbox Code Playgroud)Sob*_*que 65
我称之为"糟糕的形式",因为它根本就没有必要.你不需要在Perl中进行布尔转换.所以充其量是多余的,最糟糕的是它是一种混淆.
虽然你可以在Perl中使用一些非常好的技巧,但语言的最大问题之一(至少在感知上)是它很容易"编写一次"代码.
毕竟 - 当你可以测试标量时,为什么你需要'双否定'一个标量来得到一个布尔值?
my $state = !! 'some_string';
if ( $state ) { print "It was true\n" };
Run Code Online (Sandbox Code Playgroud)
要么:
if ( 'some_string' ) { print "It was true\n" };
Run Code Online (Sandbox Code Playgroud)
这是真的 - 由于"秘密"操作符,基于标点符号的变量等,你可以编写一些可怕的无法理解的Perl代码.它会工作得很好 - 例如 - 我仍然认为这是一个杰作:3-D Stereogram,Self replicating资源
但它不是"好代码".对于"真实世界"的使用,您的代码需要清晰,易懂且易于排除故障.
关于替代品;
while (my $line = <$F>) {
# snip
exists $counts{lines} and $counts{lines} += !! chomp $line;
}
Run Code Online (Sandbox Code Playgroud)
这是......计算你chomp认为你成功编辑一条线的频率?所以基本上它只计算输入中的行数.
为此,我会考虑"使用$.".除非我错过了你的代码的深刻内容?
"如果它没有窒息怎么办?"
好吧,好吧.怎么样:
$counts{lines}++ if foo();
Run Code Online (Sandbox Code Playgroud)
为了这:
sub foo {
my ($input) = @_;
my %responses = ( "" => "False", 1 => "True" );
return $responses{ !! $input };
}
Run Code Online (Sandbox Code Playgroud)
我会把它写成:
sub foo {
my ($input) = @_;
return $input ? "True" : "False";
}
Run Code Online (Sandbox Code Playgroud)
对于最后一个条件 - 将标志打包成一个字节:
sub flags {
my @boolean_flags = @_;
my $flags = 0;
for ( @boolean_flags ) {
$flags<<=1;
$flags++ if $_;
}
return $flags;
}
print flags ( 1, 1, 1 );
Run Code Online (Sandbox Code Playgroud)
或者,如果您正在做类似的事情 - Fcntl通过定义基于位置添加的值来了解它是如何做的,因此您不必担心位置参数问题:
您可以通过使用标记请求提供flock()常量(LOCK_SH,LOCK_EX,LOCK_NB和LOCK_UN)
:flock.
然后你可以:
flock ( $fh, LOCK_EX | LOCK_NB );
Run Code Online (Sandbox Code Playgroud)
它们按位定义,因此它们通过or运算符"添加" - 但这意味着它是幂等操作,其中设置LOCK_NB两次不会.
例如,
LOCK_UN = 8
LOCK_NB = 4
LOCK_EX = 2
LOCK_SH = 1
Run Code Online (Sandbox Code Playgroud)
如果我们将问题扩展到不那么主观:
我问的原因是要避免!!
if ( $somecondition ) { $result++ }比...更清楚$result += !! $somecondition.!!1是1,!!0是dualvar('', 0).虽然这很灵活,但它可能会让人感到惊讶,特别是因为大多数人甚至不知道双变量是什么,更不用说!返回双变量了.如果您使用三元组,则明确您获得的值:$value ? 1 : 0Dav*_*men 38
你!!利用了Perl中的两个模糊的东西:!返回的特定值,以及可能的值之一是dualvar(包含字符串和数字的标量).利用!!到复合这些行为固然精辟.虽然它的简洁性可以是一个巨大的优势,它也可以是一个相当大的减号.不要使用导致项目强制要求"在此项目中禁止使用Perl"的功能.
有很多替代方法$count += !! (some_expression)可以计算该表达式的真实值的出现次数.一个是三元组$count += (some_expression) ? 1 : 0.这也有点模糊.有一个很好的紧凑方式来做你想要的,这是使用post-if:
$x++ if some_expression;
Run Code Online (Sandbox Code Playgroud)
这恰恰说明了你在做什么.
nwe*_*hof 19
整个问题有些主观,所以我想提出一个与迄今为止发布的其他答案不同的意见.我不会考虑一般的双重否定形式,但如果有更可读的替代方案,我会尽量避免它.关于你的例子:
使用类似的东西$count++ if $condition.
真值是否为哈希键?那简直就是邪恶.至少,对于必须维护代码的人来说,这是令人惊讶的.
在这里使用!!是合理的.
在这里,我将使用三元运算符.execute传递双变量时的行为并不十分清楚.
另一种可以完全正常使用的情况!!是将某些值转换为布尔值,例如在return语句中.就像是:
# Returns true or false.
sub has_item {
my $self = shift;
return !!$self->{blessed_ref};
}
Run Code Online (Sandbox Code Playgroud)
大多数程序员应该知道!!静态类型语言中的习惯用语,它通常用作强制转换为强制转换.如果这就是你想要做的事情并且没有不必要的副作用的危险,那就去做双重否定.
也许只有你看到的代码并没有那么糟糕.
但是,您的开发人员可能会在某天修复代码中的错误,并偶然发现错误.有两种选择
!,使你的代码无效!!.重构一些其他代码后,它突然挂起......类型不匹配?无论哪种方式,它都会浪费未来开发人员的时间,除非他们碰巧熟悉它.可理解的代码永远不会为你自己(好吧,它可以帮助),但对于任何其他人将看到你的代码.