perl表达式“或”和子例程“isa”

时间:2013-05-22 06:50:43

标签: perl isa

我遇到了这段代码,但我不明白。

$type->isa('UNIVERSAL')
  or eval "require $type"
    or croak $@;
  1. 我已提到perldoc,我知道子例程isa()正在检查$type是否已被祝福UNIVERSAL。但事实上,所有Perl类都是UNIVERSAL的子类,对吧?

  2. 我对两个or术语感到困惑。他们是什么意思?

4 个答案:

答案 0 :(得分:3)

    此处
  1. isa被滥用以检查某个包是否已导入requireuse。如果packcage Package->isa('UNIVERSAL')存在,Package将返回true,否则为false。

  2. or正以short circuit身份使用。在表达式a or b中,如果b具有真值,则不会评估a。如果术语是变量,这没有区别,但如果它们是具有副作用的子程序调用,那么它就成为if语句的替代。

    有问题的陈述与此代码相同

    unless ($type->isa('UNIVERSAL')) {
      unless (eval "require $type") {
        croak $@;
      }
    }
    

    总体效果是检查变量$type指定的模块是否已导入。如果没有,则使用require导入它,如果失败则调用croak

答案 1 :(得分:3)

链式or旋律

Perl的or运算符的工作方式与||类似,但优先级非常低,即它与周围代码的“紧密”程度。逻辑或Perl短路,即一旦操作数评估为真,评估就会停止。

Perl中常见的习惯用法是使用短路进行流量控制,通常与错误处理有关,如

open my $fh, "<", $path or die "$0: open: $!";

成功时,open返回一个真值。当or至少有一个操作数为真时open的结果为真,那么在成功的die上,perl不会or,因为or的右边操作数是my $name = shift or "Bruce"; 没有评估。

my $name = shift or given_name $family_name or "Bruce"; 运营商的链可以任意扩展。这对于指定默认值很有用。在简单的情况下,这看起来像

$type->isa('UNIVERSAL')
  or eval "require $type"
    or croak $@;

如果您有多个后备案例,请按照您想要尝试的顺序将它们放入。

$type->isa('UNIVERSAL')

成功的第一个案例获胜。

代码

eval "require $type"

就是这样一个链条。评估按以下顺序进行:

  1. croak $@
  2. $type
  3. $type
  4. 如果require是已存在的包的名称,则忽略步骤2和3。

    到达第2步意味着未加载require,因此现在代码尝试croak它。如果$obj->isa( TYPE )成功,则忽略第3步。

    达到第3步意味着该包不存在且无法加载。在这种情况下,CLASS->isa( TYPE )输出失败的原因并退出程序。

    是否已加载某个模块?

    当作为方法调用时,isa有三种形式:

      
        
    • eval { VAL->isa( TYPE ) }
    •   
    • CLASS->isa( TYPE )
    •   
    • isa
    •   

    第三个是通用的全能,与此无关。第一个是你在问题中描述的内容。

    第二个记录为

      

    当用作类方法(or)时,有时也称为静态方法),如果 CLASS 继承自(或本身),则my $type = $CLASSES_OF{ $class }->{ $name } or croak "No class given for $name"; 返回true软件包的名称​​ TYPE 或继承自软件包 TYPE

    ::_factory, from SOAP::WSDL::XSD::TypeLib::ComplexType$type链之前的行是

    isa

    这里,$type的值是一个字符串,因此isa正在检查名为require的类是否继承自UNIVERSAL。正如您在问题中所述,所有类都继承自UNIVERSAL。

    那是怎么回事?如果isa失败,则代码会调用%Foo::Bar::Baz::Quux::,因此sub package_exists { my($pkg) = @_; $pkg =~ s/::$//; my @parts = split /::/, $pkg; my $stash = $main::{"main::"}; while (@parts) { my $subpkg = shift(@parts) . "::"; return unless exists $stash->{$subpkg}; $stash = $stash->{$subpkg}; } $stash; } 检查的目的必须是确定是否已加载给定的类。

    是否存在某个包?

    请记住,Perl类和Perl包密切相关。对于要存在的类,必须存在同名的包。非破坏性地检测包是否存在变得棘手。探测藏匿require直接自动生成。 Perl按层次存储stashes,所以你必须像

    一样进行洞察
    %INC

    成功isa修改名为%INC的特殊哈希。我不确定代码为什么不检查bool Perl_sv_derived_from_pvn(pTHX_ SV *sv, const char *const name, const STRLEN len, U32 flags) { dVAR; HV *stash; PERL_ARGS_ASSERT_SV_DERIVED_FROM_PVN; SvGETMAGIC(sv); if (SvROK(sv)) { const char *type; sv = SvRV(sv); type = sv_reftype(sv,0); if (type && strEQ(type,name)) return TRUE; stash = SvOBJECT(sv) ? SvSTASH(sv) : NULL; } else { stash = gv_stashsv(sv, 0); if (!stash) stash = gv_stashpvs("UNIVERSAL", 0); } return stash ? isa_lookup(stash, name, len, flags) : FALSE; } 。也许某些类型是在require机制之外加载的,或者作者对这个令人愉快的小黑客很满意。

    考虑sv_derived_from的来源,它实现"SomeClass"->isa("UNIVERSAL")

    sv

    请记住,我们正在使用

    调用此代码
    "SomeClass"

    所以SvROK包含字符串svelse检查stash是否为引用,而不是字符串,因此我们始终位于NULL分支中。

    最后,{{1}}的值始终为非{{1}}:如果已加载包,则指向包的符号表,否则指向UNIVERSAL。查找成功加载包,否则失败。亲自尝试一下:

    $ perl -le 'print "strict"->isa("UNIVERSAL") ? "loaded" : "not loaded"'
    not loaded
    
    $ perl -Mstrict -le 'print "strict"->isa("UNIVERSAL") ? "loaded" : "not loaded"'
    loaded

答案 2 :(得分:2)

问题1

对于Perl中的所有类,

UNIVERSAL is the base class

问题2

Perl中的

orlow precedence operator,意思是

    如果A or B为真,或者A为真,则
  • B true ,这意味着,如果两个条件中的任何一个为真。
  • 低优先级表示上面的A表达式在<{em> or之前进行评估,前提是A运算符优先级更高比or。可能是这种情况,因为or(与||不同)在Perl中具有最低优先级。

在Perl中,给出表达式

A or B or C;
仅当B false 时才处理(评估)

A 仅当C false 时才会处理(评估)B

在您的情况下,如果$type->isa('UNIVERSAL') true ,则Perl会在此处停止并考虑整个表达式 true 。如果 false ,它将评估eval "require $type":如果为true,则整个表达式为true,如果 false ,则最终评估croak $@

这是一种快速的方法

 if ( ! $type->isa('UNIVERSAL')) {
    if ( ! eval "require $type") {
       croak $@;
    }
 }

答案 3 :(得分:1)

or,只有当左侧执行返回non-false value

时,perl才会执行右侧句子