首页 > 解决方案 > UNIVERSAL 中“角色”的定义是什么?Perl 角色如何工作?

问题描述

Perl 有一个名为的内部伪模块UNIVERSAL,所有模块都从该模块继承。它有一个名为 的方法DOES,从docs on 开始UNIVERSAL

$obj->DOES( ROLE )

CLASS->DOES( ROLE )

DOES检查对象或类是否执行角色ROLE。角色是一组命名的特定行为(通常是特定名称和签名的方法),类似于一个类,但它本身不一定是一个完整的类。例如,日志记录或序列化可能是角色。

DOES并且isa相似,如果其中任何一个为真,您就知道调用该方法的对象或类可以执行特定的行为。然而,DOES它的不同之处isa在于它不关心 invocand 如何执行操作,只关心它。(isa当然要求继承关系。其他关系包括聚合、委托和模拟。)

角色和类之间存在关系,因为每个类都意味着存在同名角色。继承和角色之间也存在关系,从祖先类继承的子类隐式地执行其父类执行的任何角色。因此,您可以安全地使用DOES代替isa,因为它将在所有将返回 true 的地方isa返回 true(前提是任何重写DOESisa方法行为适当)。

我知道 Moose 等人提供了一个DOES,并且我了解它是如何使用的。但从某种意义上说,a 是UNIVERSAL::DOES什么ROLE?他们是如何被追踪的?除了 Moose 之外,它们是如何被创造出来的DOES呢?我尝试查看源代码,但未提供的实现DOES。这是perl中的ROLE东西的概念吗?CORE这似乎与(also / )perldoc perlapi的提及有关sv_does_svsv_doessv_does_pv

sv_does_sv返回一个boolean指示是否SV执行特定的命名角色。SV可以是 Perl 对象或 Perl 类的名称。

bool sv_does_sv(SV* sv, SV* namesv, U32 flags)

我可以sv_does_sv. universal.cSV 角色的定义是什么?我在哪里可以找到有关此的更多信息?

从用户层面来看,这里的代码是做什么的,(这是一个子引用)

UNIVERSAL->can('DOES')

返回的地址UNIVERSAL->can('isa')与同一次调用中的地址不同,所以它做的事情不同,我可以在上面的链接中看到那个垃圾universal.c

标签: perlrolesuniversal

解决方案


UNIVERSAL::DOES相当于:

sub DOES {
   croak "Usage: invocant->DOES(kind)"
       if @_ != 2;
   $_[0]->isa($_[1]);
}

在内部,在传递的第一个 SV 上sv_does_sv调用该方法。isaperl 本身不提供角色的实现,因此留给角色模块来DOES为它们提供解释。

Moose、Moo、Role::Tiny、Mouse 等中的约定是,该DOES方法对于类及其父类以及类及其父类组成的角色都是正确的。这些库还提供了does方法,该方法仅适用于类及其父类的组合角色,而不适用于类或其父类。


推荐阅读