Perl多态性如何工作?

use*_*021 7 perl

我无法弄清楚多态如何在Perl中工作的解释.我理解多态性意味着什么,但我想弄清楚它在perl中的内部工作原理.有人能指出一些解释它的文档.我所做的所有谷歌搜索都给出了perl中多态性的例子,但不是perl如何使其工作.

Bor*_*din 15

当在对象或类上调用方法时,Perl会查看该方法是否由类本身直接提供.

因为类只是Perl包,所以只需要查找子例程的存在&Class::method.

如果没有找到这样的子例程,Perl会检查@ISA同一个包(即@Class::ISA)中包含该类的基类列表的数组,并对其中出现的每个包/类进行相同的检查.

这些类中的每一个依次也可以有一个@ISA数组,因此搜索是递归的.

最后,如果通过此方法找不到该方法,Perl会在特殊包中UNIVERSAL查找子例程&UNIVERSAL::method.

此时失败继续调用AUTOLOAD系统,但这实际上超出了多态性的原则.

无法在任何地方找到合适的匹配方法会引发异常.


Lum*_*umi 9

面向对象Perl的第7章,Damian Conway,Manning(2000)被称为多态.十页.

但是,请注意,如果您来自C++或Java或C#或类似的,那么Perl中的"多态性"并不是很多.我甚至会说多态性的概念比Perl中的事情更复杂.

我认为Perl程序员应该努力理解的机制是方法查找的工作原理.答案是:深度优先递归扫描@ISA包的数组.

举个例子,我们来做$o->bla.我们$o有幸得到了A包,没有实现bla.但它继承自first B和then C(@ISA = ('B', 'C')).所以我们先做一下查找B.它也没有定义方法.如果它有父类,我们将继续在那里查找.但事实并非如此.所以我们现在调查一下C,幸运的是它确实有方法,否则这将是一个运行时错误,因为最后的包UNIVERSAL,也没有定义bla.


ike*_*ami 5

对象方法调用基本上是以下内容的优化*版本:

my $class = ref($_[0]);
my @isa = mro::get_linear_isa($class);
for my $pkg (@isa) {
   if (exists(&{$pkg.'::'.$method_name})) {
       return &{$pkg.'::'.$method_name};
   }
}
Run Code Online (Sandbox Code Playgroud)

ref获取与对象关联的类的名称。该类存储在对象的变量中。

$ perl -MDevel::Peek -e'my $o = {}; Dump($o); bless($o, "SomeClass"); Dump($o);'
SV = IV(0x9e4ae0c) at 0x9e4ae10
  REFCNT = 1
  FLAGS = (PADMY,ROK)
  RV = 0x9e317d0
  SV = PVHV(0x9e36808) at 0x9e317d0
    REFCNT = 1
    FLAGS = (SHAREKEYS)
    ARRAY = 0x0
    KEYS = 0
    FILL = 0
    MAX = 7
    RITER = -1
    EITER = 0x0
SV = IV(0x9e4ae0c) at 0x9e4ae10
  REFCNT = 1
  FLAGS = (PADMY,ROK)
  RV = 0x9e317d0
  SV = PVHV(0x9e36808) at 0x9e317d0
    REFCNT = 1
    FLAGS = (OBJECT,SHAREKEYS)        <----
    STASH = 0x9e323d0   "SomeClass"   <----
    ARRAY = 0x0
    KEYS = 0
    FILL = 0
    MAX = 7
    RITER = -1
    EITER = 0x0
Run Code Online (Sandbox Code Playgroud)

get_linear_isa基于@ISAin package $class@ISA其中命名的包。

由于类名称位于对象中,并且Perl可以在运行时检查其符号表,因此不需要虚拟方法表来提供多态性。

* —缓存哪个包为类$ class提供了方法$ method_name。此外,它当然不会预先计算整个线性ISA,而是根据需要计算。