perl中的UNIVERSAL 和AUTOLOAD
看到intermediate perl 14章,里面提到几个问题, 在网上的一些帖子(其他书)上看到一些和书上不对应的地方,于是自己测试了一下,inter perl上写的是正确的。
梳理一下如下:
Do all objects inherit from a common class?
答:是的,perl中设定了一个类叫做 UNIVERSAL类, 在这个类中的定义的方法,被所有类继承,是最基本的类(不能乱用)。
what if a method is missing ? 如果一个方法不存在,会怎么样:
答:这个问题从两方面说:
一方面, perl提供了测试的方法,即UNIVERSAL类中有三个方法isa(),can() 和VERSION(). 所有的类都能调用这三个方法(最好别重写)
例1
比如有一个对象 $tv_horse 是一个Horse对象, 可以用$tv_horse->isa('Horse') 测试,返回值为true,
如果tv_horse是一个 racehorse的对象,是horse的派生类,也是正确的。
例2
$tv_horse->can('swim'); 首先假定tv_horse是一个类对象或者类名, 这样就是判断该类中是否有swim方法。
另一方面,由于有继承存在,在测试method 是否missing的过程是一个搜索的过程,
先寻找自己再寻找基类,一路追查下去,RACEhorse 找horse ,horse 找animal,
最后找到 UNIVERSAL类。
如果都没有找到,can方法会返回false;
但是如果不是测试,而是直接调用, 例如:$tv_horse->swim(@arg),这种 方式,除了从下到上找一遍,perl还会寻找并尝试调用 这些类中的AUTOLOAD方法, 并将参数都传给该方法的@_变量中;并且 our $AUTOLOAD 变量存储着 packagename::methodname ;这个例子就是 RACEHORSE::swim 。
即直接调用,有可能搜索两遍。
可以用下面的代码修改看打印顺序。
#!/bin/perl
{
package Grandpa;
$name = "Gramps";
sub greetme {
print "greetme in grandpa\n";
}
sub AUTOLOAD {
print "autoload in grandpa package.[autoload]\n";
}
}
{ package Parent;
our @ISA =qw(Grandpa);
sub greetme {
print "greetme in parents\n";
}
sub AUTOLOAD {
print "autoload in parent package.[autoload]\n";
}
}
{
package UNIVERSAL;
sub greetme{
print "greeta in Universal\n";
}
sub AUTOLOAD {
print "autoload in Universal package.[autoload]\n";
}
}
print Parent->can('greetme') ? "can\n":"cann't\n";
Parent->greetme();
总结: 测试的时候,要确定变量是 either a blessed reference or a class name as a scalar ,直接调用的时候也是如此;不能确定就用eval{}
测试和autoload无关,调用才可能找到autoload。
把基本用不到的方法放在autoload里,再用eval q{ sub swim{ ...}}; goto &swim 配合使用,可以节约编译的时间。
调用方法会先找UNIVERSAL 再找AUTOLOAD,书中练习题2也印证了这一点。