是否有系统的方法来检查`strict refs`?

Posted

技术标签:

【中文标题】是否有系统的方法来检查`strict refs`?【英文标题】:Is there a systematic way to check for `strict refs`? 【发布时间】:2014-06-01 08:21:24 【问题描述】:

过去几年,我们在旧版 Perl 代码库中采用了use strict。我的任务是把它添加到其余的模块中,同时确保它当然不会破坏任何东西。

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

当然,我可以通过在所有可能的情况下(即完全覆盖)调用所有函数来引发运行时错误,但这很麻烦,尤其是。因为这段代码缺少单元测试。如果您有更好的想法,我将不胜感激。

【问题讨论】:

现在我正在查找/[@%$]\s*[$]/ 的源代码,它可以找到我知道的所有取消引用语法。然后我手动检查每个事件。 我就是这样做的。但也要寻找/->\s*[[]/ 虽然我会拒绝这项任务并说必须先进行单元测试 (完全覆盖是不够的。例如,您可以通过运行$x=0;$y=0;$x=1;$y=1; 获得$r = $x ? [] : "abc"; return if !$y; push @$r, "def"; 的完整测试覆盖,但这不会发现$x=0;$y=1; 的问题。 ) 【参考方案1】:

因为 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 中,您现在有一小段代码,您可以在其中确信每个变量的数据类型。逐步添加这样的断言可以让您不断扩大“信心区域”。

请注意,上面的小改动意味着我们的代码现在将有 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 有一个静态类型系统,它就可以了。它也许不能证明会有问题,但如果它不能证明没有任何问题,那就足够警告了。在这里,foo 的类型为 Dict[name => Str] -> Bool$var 的类型是 Dict[name => Str] | Str 的 sum 类型(在大多数静态类型语言中隐式使用时是非法的)。我们可以看到这个可能作为foo的参数是合法的,但是在这种类型的实例中情况并非如此——任何理智的编译器都会拒绝它。 我的意图是“静态分析无法捕获那种东西”被“因为 Perl 是无类型的”(在上一段中)限定的。我会澄清的。

以上是关于是否有系统的方法来检查`strict refs`?的主要内容,如果未能解决你的问题,请参考以下文章

如何检查 ref 游标是不是从 pl/sql 过程返回数据

关于vue.js element ui 表单验证 this.$refs[formName].validate()的问题

VUE3响应工具集

严格模式(Strict Mode)

是否有通用的 linux 实用程序/方法来查询有关系统上所有磁盘的信息?

是否有更快的方法来检查是否存在数千个 NSManagedObject 项目?