什么是“最好的”使用方式“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