为什么“!!”在Perl中被认为是不好的forms?
在最近的求职面试过程中,我提交了一些使用所谓的“秘密”的示例Perl代码!!
操作员 。 后来在讨论代码的时候,其中一位面试官问我为什么select使用这个代码,并表示它被认为是不好的forms。 他没有详细说明为什么。
我和我的团队多年来一直在使用这个运营商,却从未意识到它被认为是“糟糕的forms”。
“砰砰”的操作员是否有副作用或其他意外行为? 为什么或者可能会被某些人认为是“坏forms”? 有没有惯用的select?
下面是我会考虑的几个例子!!
可接受的和/或可取的。
-
编码练习中的实际代码,这是添加布尔值的一个例子:
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; }
-
您需要为外部库/进程(如数据库)使用一个types转换,只考虑某些值是真实的:
my $sth = $dbh->prepare("INSERT INTO table (flag,value) VALUES (?,?)") $sth->execute("i_haz_cheeseburger", !! $cheeseburger_string)
你的!!
利用了Perl中两个晦涩的东西:具体的值!
返回,并且可能的值之一是dualvar(一个包含string和数字的标量)。 使用!!
复合这些行为是公认的精辟。 虽然它的精髓可以是一个巨大的优势,但它也可以是一个相当大的减去。 不要使用导致项目强制要求“在该项目上禁止使用Perl”的function。
有很多替代$count += !! (some_expression)
$count += !! (some_expression)
来计算该expression式的真值的发生。 一个是三元, $count += (some_expression) ? 1 : 0
$count += (some_expression) ? 1 : 0
。 这也有点模糊。 有一个很好的紧凑的方法来做你想做的,就是使用post-if:
$x++ if some_expression;
这就是说你在做什么。
我会把它叫做“坏forms”,因为它根本就没有必要。 你不需要在Perl中进行布尔转换。 所以最好是多余的,最坏的情况是混淆。
虽然在Perl中可以使用一些非常好的技巧,但是语言中最大的问题之一(至less感觉上)是它很容易“写一次”代码。
毕竟,当你可以testing标量的时候,为什么你需要“双否定”一个标量来得到一个布尔值呢?
my $state = !! 'some_string'; if ( $state ) { print "It was true\n" };
要么:
if ( 'some_string' ) { print "It was true\n" };
确实如此 – 由于“秘密”操作符,基于标点符号的variables等,您可以编写一些令人恐惧的难以理解的Perl代码。而且,它可以正常工作 – 例如 – 我仍然认为这是一个杰作: 三维立体图,自我复制资源
但这不是“好代码”。 对于“真实世界”的用法,您的代码需要清晰,易懂,易于排除故障。
关于替代方法;
while (my $line = <$F>) { # snip exists $counts{lines} and $counts{lines} += !! chomp $line; }
这是…计算你已经成功地chomp
了我认为的一条线? 所以基本上它只是计算你的input行数。
为此,我会考虑使用$.
”。 除非我错过了你的代码深刻的东西?
“如果它不是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
来看,通过定义基于位置的值来添加值,所以你不必担心位置参数问题:
您可以使用标签
: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
如果我们把这个问题扩大到较不主观的问题:
我正在要求避免的原因!
- Perl评估variables的“真实性”,所以实际上并不需要太多的逻辑布尔值。
- 条件语句比等价的布尔代数更清晰。
if ( $somecondition ) { $result++ }
比$result += !! $somecondition
更清晰$result += !! $somecondition
$result += !! $somecondition
。 - 这是一个秘密的运营商名单, 因为它是模糊的。 您未来的维护程序员可能不会理解这一点。
-
!!1
是1
,!!0
是dualvar('', 0)
。 虽然这是相当灵活的,但它可能会令人惊讶,特别是因为大多数人甚至不知道什么是dualvar,更不用说了!
返回一个。 如果你使用三元组,那么显式的值是什么:$value ? 1 : 0
$value ? 1 : 0
整个问题有点主观,所以我想提出一个不同于迄今发布的其他答案的意见。 一般来说,我不会考虑双重否定的不良forms,但如果有更可读的select,我会尽量避免它。 关于你的例子:
-
$count++ if $condition
使用$count++ if $condition
。 -
真值作为散列键? 那简直是邪恶的 至less,任何需要维护你的代码的人都会感到惊讶。
-
这里使用
!!
是有道理的。 -
这里我使用三元运算符。 当传递双variables时,
execute
行为是不是很清楚。
另一种情况,完全可以使用!!
在将某些值转换为布尔值时,例如在返回语句中。 就像是:
# Returns true or false. sub has_item { my $self = shift; return !!$self->{blessed_ref}; }
大多数程序员应该知道!!
静态types语言的习惯用法,它经常被用来作为一个强制types的布尔。 如果这就是你想要做的,没有不必要的副作用的危险,去双重否定。
也许对于只有你看到的代码来说并不是那么糟糕。
但是,您的开发人员可能会在某天在您的代码中修复一个错误,并且会发现这个错误。 有两个选项
- 他认为你犯了一个错误,并删除一个
!
,使你的代码无效 - 他认为这只是软件腐烂,并删除两个
!!
没有第二个想法。 重构一些其他的代码后,它突然挂在…types不匹配?
无论如何,这将浪费未来开发者的时间,除非他们碰巧熟悉它。 智能代码从来就不是你自己的(好吧,这可能会有所帮助),但对于任何其他谁将会看到你的代码。
根据工作的不同,这对很多商业和面试的原因都是不利的。
- 当处理一个团队项目或其他许多其他开发人员可以在其上工作的代码时,不要混淆(或遵循公司策略)
- 说什么圣训,会造成更多的工作,并没有清楚地显示代码的意图。
- 这是不必要的,正如上面所讨论的那样 – 听起来至less有一种情况是结果不起作用 – 因此是一个错误。
- 在面试中显示了不明确编码的用法,而在面试中更容易和更明确的方式并不看好。
- 面试是你想表明你是一个团队的一个地方,而不是你要鞭挞出一个别人没有意识到的怪异的东西(除非它碰巧是一个未解决的问题的答案)
如果问采访者为什么他认为这是“糟糕的forms”,那么这样的forms就会很好。 一个方便的面试后续提示,将是送他一个谢谢你,问他为什么认为这是“坏forms”