perl表达式"或"和子例程"isa"

wuc*_*ang 5 perl isa

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

$type->isa('UNIVERSAL')
  or eval "require $type"
    or croak $@;
Run Code Online (Sandbox Code Playgroud)
  1. 我已经提到了perldoc,我知道子程序isa()正在检查是否$type已经祝福包装UNIVERSAL.但实际上,所有Perl类都是子类UNIVERSAL,对吧?

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

Gre*_*con 3

连锁or旋律

\n\n

Perl\xe2\x80\x99sor运算符的工作方式与此类似||,但优先级非常低,即 \xe2\x80\x9ctightly\xe2\x80\x9d 它如何绑定到周围的代码。Perl 中的逻辑或短路,即一旦操作数计算为真,计算就会停止。

\n\n

Perl 中的一个常见习惯用法是使用短路来进行流控制,通常与错误处理相关,如下所示

\n\n
open my $fh, "<", $path or die "$0: open: $!";\n
Run Code Online (Sandbox Code Playgroud)\n\n

成功后,open返回真值。or当至少一个操作数为 true 时,结果为true,因此在成功时open,perl 不会成功,die因为右侧操作数 toor未求值。

\n\n

运营商链or可以任意延伸。这对于指定默认值很有用。在简单的情况下,看起来像

\n\n
my $name = shift or "Bruce";\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
my $name = shift or given_name $family_name or "Bruce";\n
Run Code Online (Sandbox Code Playgroud)\n\n

第一个成功的案件获胜。

\n\n

代码

\n\n
$type->isa(\'UNIVERSAL\')\n  or eval "require $type"\n    or croak $@;\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
    \n
  1. $type->isa(\'UNIVERSAL\')
  2. \n
  3. eval "require $type"
  4. \n
  5. croak $@
  6. \n
\n\n

如果$type是已存在的包的名称,则忽略步骤 2 和 3。

\n\n

到达步骤 2 意味着$type尚未加载,因此现在代码尝试require加载。如果require成功,则忽略步骤 3。

\n\n

到达步骤 3 意味着该包不存在并且无法加载。在这种情况下,croak输出失败的原因并退出程序。

\n\n

是否加载了某个模块?

\n\n

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

\n\n
\n
    \n
  • $obj->isa( TYPE )
  • \n
  • CLASS->isa( TYPE )
  • \n
  • eval { VAL->isa( TYPE ) }
  • \n
\n
\n\n

第三个是通用的包罗万象,与这里无关。第一个是你在问题中所描述的。

\n\n

第二个记录为

\n\n
\n

当用作类方法 ( CLASS->isa( TYPE ))(有时称为静态方法)时,isa如果CLASS继承(或其本身)包TYPE的名称或继承自包TYPE ,则返回 true 。

\n
\n\n

来自 SOAP::WSDL::XSD::TypeLib::ComplexType 的or链之前的行是::_factory

\n\n
my $type = $CLASSES_OF{ $class }->{ $name }\n    or croak "No class given for $name";\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

那么\xe2\x80\x99s 发生了什么?如果isa失败,代码将调用require,因此检查的目的isa必须是确定是否已加载给定的类。

\n\n

是否存在某个特定的包?

\n\n

请记住,Perl 类和 Perl 包密切相关。为了使类存在,必须存在同名的包。非破坏性地检测包是否存在是很棘手的。直接探测藏匿处%Foo::Bar::Baz::Quux::会自动复活。Perl 分层存储存储,因此您\xe2\x80\x99d 必须像下面这样进行探索

\n\n
sub package_exists {\n  my($pkg) = @_;\n  $pkg =~ s/::$//;\n  my @parts = split /::/, $pkg;\n\n  my $stash = $main::{"main::"};\n  while (@parts) {\n    my $subpkg = shift(@parts) . "::";\n    return unless exists $stash->{$subpkg};\n    $stash = $stash->{$subpkg};\n  }\n\n  $stash;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

成功修改名为%INCrequire的特殊哈希。我\xe2\x80\x99m 不确定为什么代码不\xe2\x80\x99t 检查。也许某些类型是在 require 机制之外加载的,或者作者可能对这个令人愉快的小技巧感到满意。%INC

\n\n

sv_derived_from考虑实现 的来源isa

\n\n
bool\nPerl_sv_derived_from_pvn(pTHX_ SV *sv,\n                         const char *const name, const STRLEN len,\n                         U32 flags)\n{\n    dVAR;\n    HV *stash;\n\n    PERL_ARGS_ASSERT_SV_DERIVED_FROM_PVN;\n\n    SvGETMAGIC(sv);\n\n    if (SvROK(sv)) {\n        const char *type;\n        sv = SvRV(sv);\n        type = sv_reftype(sv,0);\n        if (type && strEQ(type,name))\n            return TRUE;\n        stash = SvOBJECT(sv) ? SvSTASH(sv) : NULL;\n    }\n    else {\n        stash = gv_stashsv(sv, 0);\n        if (!stash)\n            stash = gv_stashpvs("UNIVERSAL", 0);\n    }\n\n    return stash ? isa_lookup(stash, name, len, flags) : FALSE;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

请记住,我们正在调用此代码

\n\n
"SomeClass"->isa("UNIVERSAL")\n
Run Code Online (Sandbox Code Playgroud)\n\n

sosv包含字符串"SomeClass". SvROK检查是否sv是引用,而字符串则不是,所以我们总是在else分支中。

\n\n

最后, 的值stash将始终为非NULL: 指向包的符号表(如果已加载)或 UNIVERSAL 否则。对于已加载的包,查找成功,否则查找失败。自己尝试一下:

\n\n
$ perl -le \'print "strict"->isa("UNIVERSAL") ? "已加载" : "未加载"\'\n未加载\n\n$ perl -Mstrict -le \'print "strict"->isa("UNIVERSAL") ? "已加载" : "未加载"\'\n已加载
\n