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