有没有系统的方法来检查`严格的参考`?

时间:2014-04-17 07:10:58

标签: perl reference use-strict

在过去的几年里,我们在传统的Perl代码库中采用了use strict。我的任务是将其添加到剩余的模块中,同时确保它不会破坏任何内容。

现在use strict 'vars'use strict 'subs'这很容易,因为这些是简单perl -c捕获的编译时错误。但有没有系统的方法来检查由use strict 'refs'触发的运行时错误?

当然,我可以通过在所有可能的情况下调用所有函数来激发运行时错误(即完全覆盖),但这是麻烦的。因为这段代码缺乏单元测试。如果你有更好的主意,我将非常感激。

1 个答案:

答案 0 :(得分:4)

因为Perl是无类型的(变量可能包含引用或非引用),所以只能在运行时检查它。考虑:

use strict;

# Usage: foo(HASHREF)
sub foo {
   print $_[0]{name}, "\n" if int(rand(2));
}

my $var = int(rand(2))
   ? { name => "Hello" }
   : "World";  # oopsie!

foo($var);

大约25%的时间会失败。对无类型语言进行静态分析无法捕捉到这种情况 - 它只能被您的测试套件捕获,所以您应该优先考虑改进它。

也就是说,有一些方法可以改进可以帮助你的代码。例如,如果我们对传入的参数进行类型检查,我们可以证明foo子本身是正确编写的:

sub foo {
   my $href = $_[0];
   ref($href) eq 'HASH' or die("Expected hashref!");
   print $href->{name}, "\n" if int(rand(2));
}

这有助于确保foo行为的foo行为的正确性,并转移到foo的来电者身上。在foo范围内,您现在可以使用一些环形围栏代码,您可以对每个变量的数据类型充满信心。逐步添加这样的断言可以让你不断扩大“#34;置信区域”。

请注意,上面的小改动意味着我们的代码现在会在50%的时间内失败,而不是25%的时间。由于foo现在失败的程度更高,这将有助于我们捕获错误的真实来源:

my $var = int(rand(2))
   ? { name => "Hello" }
   : "World";  # oopsie!

foo($var);

部分是因为我写了它,部分是因为它是damn fast,我建议您查看Type::Params来检查子参数。以下是如何使用它的示例:

use feature qw(state);
use Types::Standard qw( HashRef );
use Type::Params qw( compile );

sub foo {
   state $signature = compile( HashRef );
   my ($href) = $signature->(@_);
   print $href->{name}, "\n" if int(rand(2));
}

将其扩展为带有多个参数的子...

use feature qw(state);
use Types::Standard qw( -types );
use Type::Params qw( compile );

sub query_get_rows {
   state $signature = compile( InstanceOf['DBI::db'], Str, Optional[Int] );
   my ($dbh, $query, $limit) = $signature->(@_);

   # do stuff here
}