我遇到了这段代码,但我不明白。
$type->isa('UNIVERSAL')
or eval "require $type"
or croak $@;
我已提到perldoc
,我知道子例程isa()
正在检查$type
是否已被祝福UNIVERSAL
。但事实上,所有Perl类都是UNIVERSAL
的子类,对吧?
我对两个or
术语感到困惑。他们是什么意思?
答案 0 :(得分:3)
isa
被滥用以检查某个包是否已导入require
或use
。如果packcage Package->isa('UNIVERSAL')
存在,Package
将返回true,否则为false。
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"
就是这样一个链条。评估按以下顺序进行:
croak $@
$type
$type
如果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
包含字符串sv
。 else
检查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中的所有类,问题2
Perl中的 or
是low 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