16

最近,我决定开始在我的代码中更频繁地使用Perl::Critic 。在使用 Perl 编程近 7 年之后,我已经习惯了大部分 Perl 最佳实践很长一段时间,但我知道总有改进的余地。一直困扰着我的一件事是Perl::Critic不喜欢我为子例程解压缩 @_ 的方式。举个例子:

sub my_way_to_unpack {
    my $variable1 = shift @_;
    my $variable2 = shift @_;

    my $result = $variable1 + $variable2;
    return $result;
}

这就是我一直这样做的方式,并且正如 PerlMonks 和 Stack Overflow 上所讨论的那样,它也不一定是邪恶的。

将上面的代码片段更改为...

sub perl_critics_way_to_unpack {
    my ($variable1, $variable2) = @_;

    my $result = $variable1 + $variable2;
    return $result;
}

...也可以,但我发现它更难阅读。我还阅读了 Damian Conway 的《Perl Best Practices 》一书,但我并不真正理解我喜欢的解包方法如何符合他的建议,即避免@_直接使用,正如Perl::Critic所暗示的那样。我一直认为康威在谈论肮脏,例如:

sub not_unpacking {
    my $result = $_[0] + $_[1];
    return $result;
}

上面的例子很糟糕而且难以阅读,我永远不会考虑在一段生产代码中编写它。

所以简而言之,为什么Perl::Critic认为我的首选方式不好?使用shift拆包真的犯了滔天大罪吗?

这是不是我以外的人认为应该与Perl::Critic维护者一起提出的问题?

4

5 回答 5

11

简单的答案是 Perl::Critic 在这里没有遵循 PBP。这本书明确指出,移位习语不仅可以接受,而且在某些情况下实际上是首选。

于 2010-02-16T19:15:54.703 回答
9

Running perlcriticwith--verbose 11解释了政策。不过,看起来这些解释中的任何一个都不适用于您。

总是先在第 1 行解压 @_,靠近
'sub xxx{ 我的 $aaa= 班次;我的 ($bbb,$ccc) = @_;}'。
  子例程::RequireArgUnpacking (严重性: 4)
    直接使用 `@_' 而不是将参数解包到
    局部变量首先有两个主要问题。首先,他们非常努力
    读书。如果您要通过数字而不是
    顾名思义,您还不如编写汇编代码!二、`@_'
    包含原始变量的别名!如果修改内容
    '@_' 条目,那么你正在修改你的外部变量
    子程序。例如:

       子 print_local_var_plus_one {
           我的 ($var) = @_;
           打印 ++$var;
       }
       子 print_var_plus_one {
           打印 ++$_[0];
       }

       我的 $x = 2;
       print_local_var_plus_one($x); # 打印“3”,$x 仍然是 2
       print_var_plus_one($x); # 打印“3”,$x 现在是 3 !
       打印 $x; # 打印“3”

    这是一个令人毛骨悚然的远距离动作,如果它是很难调试的
    不是故意的和有据可查的(例如“chop”或“chomp”)。

    通常的委托习语有一个例外
    `$object->SUPER::something(@_)'。只有 `SUPER::' 和 `NEXT::' 是
    识别(尽管这是可配置的)和参数列表
    委托必须仅包含 `( @_ )'。
于 2010-02-16T18:47:35.820 回答
8

重要的是要记住,Perl 最佳实践中的很多东西只是一个人对什么看起来最好或最容易使用的意见,如果你用另一种方式来做也没关系。达米安在本书的介绍性文字中说了这么多。这并不是说一切都是这样——其中有很多东西是绝对必要的:strict例如 using 。

因此,当您编写代码时,您需要自己决定自己的最佳实践是什么,并且使用 PBP 是一个很好的起点。然后与自己的标准保持一致。

我尝试遵循 PBP 中的大部分内容,但是当 Damian从我冰冷、死气沉沉的指尖撬开它们时,他可以拥有我的 subroutine-argumentshift和 my es。unless

至于 Critic,您可以选择要执行的策略,如果尚不存在,甚至可以创建自己的策略。

于 2010-02-16T18:46:28.770 回答
3

在某些情况下,Perl::Critic 不能精确地执行 PBP 指南,因此它可能会执行一个近似值,以尝试与 Conway 指南的精神相匹配。我们完全有可能误解或误用了 PBP。如果您发现有什么不合适的地方,请将错误报告发送至 bug-perl-critic@rt.cpan.org,我们会立即进行调查。

谢谢,

-杰夫

于 2010-02-17T04:24:16.320 回答
0

如果不是真的有必要,我认为您通常应该避免轮班!

刚刚遇到这样的代码:

sub way {
  my $file = shift;
  if (!$file) {
    $file = 'newfile';
  }
  my $target = shift;
  my $options = shift;
}

如果您开始更改此代码中的某些内容,则很有可能您会不小心更改班次的顺序,或者跳过一个班次,然后一切都变南了。此外,它很难阅读——因为你不能确定你真的看到了 sub 的所有参数,因为下面的一些行可能是某个地方的另一个转变......如果你在两者之间使用一些正则表达式,它们可能会替换 $_ 的内容和奇怪的事情开始发生...

使用解包 my (...) = @_ 的直接好处是您可以复制 (...) 部分并将其粘贴到您调用该方法的位置并拥有一个很好的签名:) 您甚至可以使用相同的变量- 事先命名,无需更改任何内容!

我认为 shift 意味着列表操作,其中列表的长度是动态的,并且您希望一次处理一个元素,或者您明确需要没有第一个元素的列表。但是,如果您只想将整个列表分配给 x 参数,您的代码应该使用 my (...) = @_; 没有人会怀疑。

于 2014-01-24T15:01:53.413 回答