13

我已经看到混淆和打高尔夫球的代码保持关闭以避免声明变量,并且我可以看到使用 -e 开关在命令行上跳过它们以保持单行更短。在哪些情况下您不想use strict和/或use warnings在生产代码中使用?您不想使用它们的原因是什么?

出现这个问题是因为我在这里看到有经验的 Perl 用户告诉刚接触 Perl 的人总是使用它们的帖子。

我确实在这里找到了一些相关的问题,但它们没有解释我们可能希望关闭它们的情况。

4

3 回答 3

20

pragma 将您限制为 Perl的strict一个健全的子集。一些旧功能具有历史意义(或对单行代码有好处),但在现代可读的代码库中没有位置。

strictpragma 分为三类:

  • "vars"强制您声明所有变量。这可以防止拼写错误,并确保您选择了一个范围(全局/词法)。在单行中,这并不需要那么多,因为通常只有很少的范围和很少的变量。一些单行习语不能仅与词法变量一起使用。

  • "refs"不允许 symrefs。它们对词法变量没有意义,而 Perl5 有真正的引用。所以它们通常是无用的。然而,symrefs 对于元编程仍然很有价值:

    # generate accessors
    for my $field (qw/foo bar baz/) {
      no strict 'refs';
      *{ __PACKAGE__ . '::' . $field } = sub { shift()->{$field} };
    }
    
  • "subs"强制将大多数裸字解释为子例程调用。这解决了foo . "bar"to be的歧义foo() . "bar"。如果这个类别没有被激活,并且如果foo当前没有定义 sub,那么它会被解析为"foo" . "bar". 这对 shell 程序员来说是有意义的,因为所有的裸词都是字符串。但是在 Perl 程序中,这大大增加了程序员的认知负担,而且不值得。

总结:对于没有优化可读性的简单脚本,strict "vars"并不是真正需要的。有一些情况no strict 'refs'是需要的。

pragma 允许对warnings警告消息进行细粒度控制。这对于刚接触 Perl 的程序员来说尤其重要,他们经常编写类似的东西

my %hash = { foo => 1, bar => 2 };

并想知道那把HASH(0x1234567)钥匙是从哪里来的。即使在单行上,警告也是可取的,除非您使用undef等的字符串化。

在专业的代码库中,没有理由不使用warnings 无处不在。如果脚本发出警告,则很可能存在错误,并且no warnings不会使此错误消失。warnings您对 Perl 的了解永远不会像pragma那样广博。即使是大师也会犯错误。use warnings是一个很好的调试捷径。

也就是说,可以use warnings在部署程序时发表评论。但绝不是为了发展。

根据开发团队的共识,还应使用其他 pragma:

  • no indirect禁止讨厌的new Foo方法调用。我已经看到可以在编译时使用这个 pragma 捕获的错误潜入。
  • no autovivification防止引用在只读操作(如$hash{doesnt_exist}{foo}.
于 2013-08-05T18:47:21.403 回答
9

有时strictwarnings阻止您做您想做的事情,例如对符号表进行某些会违反 的操作strict 'refs',或重新定义warnings 'redefine'将触发的子例程。在其他时候,忽略某些警告比编写针对它们的防御性代码更方便,例如针对可能包含NULL/undef会触发的值的表的快速而肮脏的数据库转储warnings 'uninitialized'

use strictuse warnings,以及它们的阻燃剂no strictno warnings可以在本地范围内,因此最好strictwarnings最小的实际范围内禁用。

@data = get_some_data_from_database();
if (some_condition()) {
    no warnings 'uninitialized';
    logger->debug("database contains: @$_") for @data;

    ## otherwise, suppressing the warnings would take something
    ## less readable and more error-prone like:
    #  logger->debug("database contains: @{[map{defined?$_:''}@$_]}") for @data
    #  logger->debug("database contains: @{[map{$_//''}@$_]}") for @data
}
# end of scope, warnings `uninitialized' is enabled again
于 2013-08-05T18:15:37.033 回答
4

use strictuse warnings帮助某人准确理解 Perl 在做什么。

始终准确地理解Perl 在做什么以及为什么(即几乎没有人)的人有资格省略它们以节省空间和可能的执行时间。不幸的是,许多想要节省空间和时间的人并不确切地知道 Perl 在做什么以及为什么,他们对 Perl 在做什么的理解是基于从其他语言中学到的许多错误假设,以至于他们绝对不应该允许忽略它们。

还有一些其他正当理由:

  • 尝试会产生您已经完全意识到的警告的行为(例如,大量递归)
  • 使用旧包(尽管我在 2000 年 7 月之后编写的任何包仍然不会产生带有use strictor的消息use warnings,所以这里的“旧”意味着非常非常旧,例如 Perl 版本 4 或更早版本)
  • 当您想利用没有人预料到的神奇 Perl 行为(但您确实希望因为您是专家)并且不想为此付出警告的代价时

顺便说一句,对于接受任何输入并基于该输入执行操作的程序,使用-T标志来帮助跟踪从用户输入中获得的可能被污染的数据的使用也非常重要。

更新:@mob 在评论中声称需要进行一些调查,即不使用严格和警告是低于甚至平均微不足道的微优化点的微优化。在以下每种情况下,使用严格和警告的实际时间为 12 毫秒,在以下每种情况下,使用它们的实际时间为 57 毫秒或更长。

因此,正如我最初所说的那样,执行时间可能会带来好处(这仅在您执行诸如在模板中嵌入 Perl 脚本并在每次加载网页时一次运行 10 或 20 个脚本时才重要,例如),但仍然建议您使用它们,除非您始终真正知道 Perl 在做什么以及为什么。我对这类“专家”的描述旨在非常接近空集。如果你认为你属于这一类,你自然不会。

[j@5 ~]$ time perl -e '1;'

real    0m0.012s
user    0m0.005s
sys     0m0.007s
[j@5 ~]$ time perl -e '1;'

real    0m0.012s
user    0m0.010s
sys     0m0.005s
[j@5 ~]$ time perl -e '1;'

real    0m0.012s
user    0m0.011s
sys     0m0.001s
[j@5 ~]$ time perl -e '1;'

real    0m0.012s
user    0m0.004s
sys     0m0.007s
[j@5 ~]$ time perl -e '1;'

real    0m0.012s
user    0m0.005s
sys     0m0.007s
[j@5 ~]$ time perl -e 'use strict; use warnings;'

real    0m0.058s
user    0m0.058s
sys     0m0.000s
[j@5 ~]$ time perl -e 'use strict; use warnings;'

real    0m0.057s
user    0m0.041s
sys     0m0.016s
[j@5 ~]$ time perl -e 'use strict; use warnings;'

real    0m0.057s
user    0m0.033s
sys     0m0.025s
[j@5 ~]$ time perl -e 'use strict; use warnings;'

real    0m0.057s
user    0m0.050s
sys     0m0.009s
于 2013-08-05T17:58:20.220 回答