为什么要使用严格和警告?


104

在我看来,如果人们使用,Perl标记中的许多问题都可以解决:

use strict;
use warnings;

我认为有些人认为它们类似于训练轮,或不必要的并发症,这显然是不正确的,因为即使是非常熟练的Perl程序员也都使用它们。

似乎大多数精通Perl的人总是使用这两个编译指示,而那些从使用它们中受益最大的人却很少使用。因此,我认为在鼓励人们使用use strict和时,有一个要链接的问题是一个好主意warnings

那么,为什么一个Perl的开发use strictwarnings


14
我一直想知道为什么这样的东西为什么他们不只是将其设置为默认值,而是让开发人员实际上必须积极地放宽东西,这是use loose;
Paul Tyng

12
就像许多有趣的有用的东西一样,Perl最初是作为一种hack,作为发明它的人的工具。后来,它变得越来越流行,越来越多的非熟练人员开始使用它。这是当您开始思考类似use strict的好主意,但向后兼容已成为您的实际问题:-(
DanielBöhmer

14
@JB Nizet,@ Paul T.,实际上,use strict;当您请求Perl 5.12(或更高版本)语言时,默认情况下处于启用状态。尝试perl -e"use v5.012; $x=123;"no strict;实际上将其关闭。
ikegami

1
尽管最终您的观点是正确的,但我们说的次数越多,也许听到的人就越多。最近有一些谣言,试图提供更多/更好/现代的Perl教程,当然严格/警告将是每一个的顶部。对于我来说,我计划在每个摘要的顶部都使用s / w,以便所有新手每次都能看到它
Joel Berger

5
@JoelBerger不,实际上没有喜欢它。就像我说的那样,标题中只有相似的词。这是为了向后兼容。是已接受答案中的第一句话,您如何建议适用于我的问题?
TLP

Answers:


83

对于初学者,use strict;(在较小程度上,use warnings;)有助于查找变量名称中的错别字。即使是经验丰富的程序员也会犯此类错误。一种常见的情况是在清理或重构代码时忘记重命名变量的实例。

使用use strict; use warnings;错误比发现错误要早得多,这使得查找错误的根本原因变得更加容易。根本原因可能是需要进行错误或验证检查,而无论程序员是否熟练,这都可能发生。

Perl警告的优点是它们很少是虚假的,因此使用它们几乎没有成本。


相关阅读:为什么使用my


2
@TLP,我不会进行研究以量化其帮助程度。只需说它们无条件地提供帮助就足够了。
ikegami

1
如果它有这么多好处,为什么将它设为可选?为什么不默认启用它(如上面的评论)?是出于兼容性原因吗?
吉恩(Jean)

4
@Jean,向后兼容。请注意,use strict;如果您使用的是5.12或更高版本的语言(use 5.012;),则默认情况下启用该功能。
ikegami 2013年

@Jean,如果您正在编写一个简单的脚本,您真的不想收到有关文件处理程序名称的警告或在使用它们之前未声明变量的警告:-)
user2676847

28

显然,use strict当您想强制perl正确编码(可能会强制声明),在字符串和subs(即裸字)上显式或谨慎使用refs时,应使用(必须)。注意:如果存在错误,则使用strict会中止执行(如果使用)。

虽然use warnings;可以帮助您找到程序中的键入错误,就像您错过了分号一样,但是您使用的是'elseif'而不是'elsif',而是使用了不赞成使用的语法或函数,诸如此类。注意:使用警告只会提供警告并继续执行,即不会中止执行。

无论如何,如果我们详细介绍一下,那会更好,我在下面指定

来自perl.com(我的最爱):

使用严格的“ vars”;

这意味着您必须在使用变量之前始终声明它们。

如果不声明,可能会收到未声明变量的错误消息

全局符号“ $ variablename”在scriptname.pl第3行需要显式的程序包名称。

这个警告意味着Perl不清楚变量的范围是什么。因此,您需要对变量进行明确说明,这意味着要么用声明它们,my以便将它们限制在当前块内,要么用完全限定的名称引用它们(例如:$ MAIN :: variablename)。

因此,如果您尝试访问至少不满足以下条件之一的变量,则会触发编译时错误:

  • 由Perl本身预先定义,例如@ ARGV,%ENV和所有全局标点变量,例如$。或$ _。

  • 用我们(对于全局)或我(对于词汇)声明。

  • 从另一个包导入。(use vars pragma伪造了一个导入,但是使用了我们的。)

  • 使用其包装名称和双冒号包装分隔符完全合格。

使用严格的“ subs”;

考虑两个程序

# prog 1
   $a = test_value;
   print "First program: ", $a, "\n";
   sub test_value { return "test passed"; }
 Output: First program's result: test_value

# prog 2
   sub test_value { return "test passed"; }
   $a = test_value;
   print "Second program: ", $a, "\n";
 Output: Second program's result: test passed

在这两种情况下,我们都有一个test_value()子项,并将其结果放入$ a中。但是,当我们运行两个程序时,我们得到两个不同的结果:

在第一个程序中,至此为止$a = test_value;,Perl不知道任何test_value()子项,并且test_value被解释为字符串'test_value'。在第二个程序中,test_value()的定义在该$a = test_value;行之前。Perl认为test_value是子调用。

对于隔离的话犹如test_value这可能是潜艇,并且可能依赖于上下文字符串的技术术语,顺便说一句,是裸字。Perl对裸字的处理可能会造成混乱,并且可能导致程序中的错误。

该错误是我们在第一个程序中遇到的错误,请记住,Perl不会期待find test_value(),所以由于尚未看到test_value(),因此它假定您需要一个字符串。因此,如果您使用use strict subs;,它将导致该程序死于错误:

在./a6-strictsubs.pl第3行使用“ strict subs”时,不允许使用标语“ test_value”。

解决该错误的方法是
1.使用括号使您清楚地知道正在调用子程序。如果Perl看到$ a = test_value();,
2.在第一次使用它之前声明它

use strict;
sub test_value;  # Declares that there's a test_value() coming later ...
my $a = test_value;  # ...so Perl will know this line is okay.
.......
sub test_value { return "test_passed"; }

3.如果要使用它作为字符串,请引用它。

因此,这种限制使Perl将所有裸字都视为语法错误。* 裸是没有上下文强制进行其他解释的任何裸名或标识符。(上下文通常是由附近的关键字或标记或通过预先声明所涉及的单词来强制执行的。)*因此,如果您打算将其用作字符串,请对其加引号;如果您打算将其用作函数调用,请对其进行预声明或使用括号。

由于这种不可预测的行为,因此标语很危险。use strict; (or use strict 'subs';)使它们可预测,因为将来可能会导致奇怪行为的裸字会使您的程序在对其造成严重破坏之前就死掉

在一个地方,即使打开了严格的subs,也可以使用裸字:分配哈希键时。

$hash{sample} = 6;   # Same as $hash{'sample'} = 6
%other_hash = ( pie => 'apple' );

哈希键中的关键字始终被解释为字符串,因此没有歧义。

使用严格的“引用”;

如果您有意或以其他方式使用符号引用,则会生成运行时错误。然后,将不是硬引用的值视为符号引用。即,该引用被解释为表示全局变量名称的字符串。

use strict 'refs';

$ref = \$foo;       # Store "real" (hard) reference.
print $$ref;        # Dereferencing is ok.

$ref = "foo";       # Store name of global (package) variable.
print $$ref;        # WRONG, run-time error under strict refs.

使用警告;

这个词法作用域的编译指示允许灵活地控制Perl的内置警告,既包括编译器发出的警告,也包括来自运行时系统的警告。

来自perldiag

因此,可以使用warnings编译指示来控制来自以下类别的大多数警告消息,即W,D和S。

(W)警告(可选)
(D)弃用(默认情况下启用)
(S)严重警告(默认情况下启用)

我已经按类别列出了一些经常出现的警告消息。有关它们和其他消息的详细信息,请参考perldiag

(W)警告(可选):

%s中
缺少参数-%c中缺少参数
(您是指&%s吗?)
(您是指“本地”而不是“我们的”吗?)
(您是指$还是@而不是%?)
'%s '不是
%s上使用的代码参考length()
在数字上错位_

(D)弃用(默认情况下启用):

已弃用define(@array)已弃用
defined(%hash)

不再支持在假条件$#中 不建议使用my()

(S)严重警告(默认情况下启用)

elseif应该是elsif
%s,它在运算符期望的位置找到
(%s之前是缺少运算符?)
(上一行缺少分号吗?)
%s从未引入过
运算符或分号

原型不匹配:%s与%s
警告:不带括号的“%s”使用不明确
无法打开%s:%s


10

这两个实用程序可以自动识别代码中的错误。

我总是在我的代码中使用它:

use strict;
use warnings FATAL => 'all';

FATAL使代码像警告一样死于警告strict

有关更多信息,请参见:严格使用警告FATAL =>'all';

还有... 根据苏斯所说的狭窄


实际上,您必须FATAL => "all"通过分配时间来延迟运行时间,$SIG{__WARN__} = sub { croak "fatalized warning @_" };否则您就搞砸了编译器,试图告诉您它需要什么。
tchrist 2011年

6
@tchrist:这一直对我和文档都有效。如果您发现无法按说明使用的情况,请使用修补文档perlbug
toolic 2011年


3

来源::不同的博客

使用将通过调用模块import()函数将函数和变量名导出到主命名空间。

编译指示是一个会影响perl的编译时或运行时行为的模块。编译指示会提示编译器。

使用警告-关于仅使用一次变量的perl抱怨,字符串到数字的不正确转换。试图写入未打开的文件。它在编译时发生。它用于控制警告。

使用strict-声明变量范围。它用于在脚本中设置某种规则。如果在代码中使用裸字,则对它们进行解释。所有变量都应指定范围,例如my,our或local。


1

“严格使用”指令告诉Perl在编译代码期间进行额外的检查。使用此伪指令将节省您调试Perl代码的时间,因为它会发现否则可能会忽略的常见编码错误。


0

严格和警告确保您的变量不是全局变量。

能够拥有各个方法唯一的变量,而不是必须跟踪每个变量名,这真是整齐。

$ _,或者某些功能没有变量,对于更快地编写更紧凑的代码也很有用。

但是,如果不使用严格警告,则$ _变为全局!


0
use strict;
use warnings;

严格和警告是perl程序的模式。它使用户可以更自由地输入代码,而且Perl代码看起来很正式,其编码标准也有效。

警告的含义与-wperl shebang行中的警告相同,因此它将为您提供perl程序生成的警告,并在终端中显示

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.