过去几年,我们在遗留的 Perl 代码库中采用了 use strict
。我的任务是将它添加到其余模块中,同时确保它不会破坏任何东西。
现在对于 use strict 'vars'
和 use strict 'subs'
这很容易,因为这些是编译时错误,一个简单的 perl -c
捕获。但是是否有系统的方法来检查由 use strict 'refs'
触发的运行时错误?
当然,我可以通过在所有可能的情况下调用所有函数(即完全覆盖)来引发运行时错误,但这尤其麻烦。因为这段代码缺少单元测试。如果您有更好的主意,我将不胜感激。
最佳答案
因为 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 本身是正确编写的:
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
中,您现在有一小段代码,您可以在其中确定每个变量的数据类型。像这样逐步添加断言可以让您不断扩大“信任区域”。
请注意,上面的小变化意味着我们的代码现在将有 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
}
关于perl - 有没有系统的方法来检查 `strict refs` ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23126760/