perl – 使用“isa”方法的最佳方式?

什么是“最好的”使用方式“isa()”可靠?换句话说,所以它可以在任何值上正确工作,而不仅仅是一个对象.

“最好的”,我的意思是缺乏未经处理的角色,以及缺乏潜在的性能问题,所以这不是一个主观问题.

This question提到了两种看起来很可靠的方法(请注意,不应该使用旧样式UNIVERSAL :: isa(),原因在于答案中记录的原因):

eval { $x->isa("Class") }
#and check $@ in case $x was not an object,in case $x was not an object

use Scalar::Util 'blessed';
blessed $x && $x ->isa($class);

第一个使用eval,第二个使用B ::(至少对于Scalar :: Util的非XS风格).

如果$x是包含类名称的标量,则第一个似乎无法正常工作,如下所示,所以我倾向于#2(使用祝福),除非somoene表示不是很好的理由.

$perl5.8 -e '{use IO::Handle;$x="IO::Handle";
  eval {$is = $x->isa("IO::Handle")}; print "$is:$@\n";}'          
1:

有没有客观的原因选择这两种方法之一(或者我不知道的第三种方法),如性能,不处理某些特殊情况等等?

解决方法

Scalar :: Util实现明确更好.它避免了eval {}的开销,它总是导致设置一个附加变量.
perl -we'$@=q[foo]; eval {}; print $@'

Scalar :: Util实现更容易阅读(它不会因为代码未知的原因而死亡).如果eval也失败了,我相信发生的是你在树之前向后走到eval之前的状态 – 这是如何实现复位状态.这带来了额外的故障开销.

基准

根本不是一个对象

Rate eval   su
eval  256410/s   -- -88%
su   2222222/s 767%   --

对象传递isa检查

Rate   su eval
su   1030928/s   -- -16%
eval 1234568/s  20%   --

对象出现故障现象检查

Rate   su eval
su   826446/s   --  -9%
eval 909091/s  10%   --

测试代码:

use strict;
use warnings;
use Benchmark;
use Scalar::Util;

package Foo;

Benchmark::cmpthese(
    1_000_000,{
        eval => sub{ eval{ $a->isa(__PACKAGE__) } },su => sub { Scalar::Util::blessed $a && $a->isa(__PACKAGE__) }
    }
);

package Bar;

$a = bless {};

Benchmark::cmpthese(
    1_000_000,{
        eval => sub{ eval{ $a->isa(__PACKAGE__)} },su => sub { Scalar::Util::blessed $a && $a->isa(__PACKAGE__) }
    }
);

package Baz;

$a = bless {};

Benchmark::cmpthese(
    1_000_000,{
        eval => sub{ eval{ $a->isa('duck')} },su => sub { Scalar::Util::blessed $a && $a->isa( 'duck' ) }
    }
);

我使用这是为i486-linux-gnu-thread-multi建立的perl,v5.10.1(*),以及Scalar :: Util,1.21

相关文章

1. 如何去重 #!/usr/bin/perl use strict; my %hash; while(...
最近写了一个perl脚本,实现的功能是将表格中其中两列的数据...
表的数据字典格式如下:如果手动写MySQL建表语句,确认麻烦,...
巡检类工作经常会出具日报,最近在原有日报的基础上又新增了...
在实际生产环境中,常常需要从后台日志中截取报文,报文的形...
最近写的一个perl程序,通过关键词匹配统计其出现的频率,让...