我试图回答这个问题,并认为我可以使用元对象协议向类添加属性.这是一个最小的例子,我尝试在构造后test向类中添加一个属性Configuration:
use v6;
class Configuration {
}
my $config = Configuration.new;
my $attr = Attribute.new(
:name('$.test'), # Trying to add a "test" attribute
:type(Str),
:has_accessor(1),
:package(Configuration)
);
$config.^add_attribute( $attr );
$config.^compose();
say "Current attributes: ", join ', ', $config.^attributes();
$attr.set_value( $config, "Hello" ); # <-- This fails with no such attribute '$.test'
say $config.test;
Run Code Online (Sandbox Code Playgroud)
当我运行这个时,我得到:
Current attributes: $.test
P6opaque: no such attribute '$.test' on type Configuration in a Configuration when trying to bind a value
in block <unit> at ./p.p6 line 16
Run Code Online (Sandbox Code Playgroud)
在类组合时间之后不能添加属性,这在编译}程序时达到结束时的编译时发生.(这是P6opaque表示的情况.表示可能存在允许这样的表示并非不可能,但此时没有指定.)
除此之外,.^add_attribute在元对象上调用,对于class属性是每个类型,而不是每个对象; 代码结构表明,期望可能是每个对象.没有任何东西可以让原型面向对象变得不可能(实际上MOP的设计使得有人可以在Perl 6中实现这样的对象系统),但是Perl 6本身并没有指定提供这一点.
因此,利用所提供的对象系统,这种操作需要在编译时和关闭之前完成}.这可以通过以下方式实现:
class Configuration {
BEGIN {
my $attr = Attribute.new(
:name('$!test'), # Trying to add a "test" attribute
:type(Str),
:has_accessor(1),
:package(Configuration)
);
Configuration.^add_attribute( $attr );
}
}
my $config = Configuration.new;
say "Current attributes: ", join ', ', $config.^attributes();
$config.^attributes[0].set_value( $config, "Hello" );
say $config.test;
Run Code Online (Sandbox Code Playgroud)
这是Perl 6动态的许多地方之一,主要是邀请程序员参与编译时,而不是在运行时使所有事情都成为可能.
最后,我将注意到有一种方法可以将属性添加到现有对象,并且基于每个对象:通过使用does将角色混合到其中.这可以通过改变对象的类型来实现.还有一些文档does 在这里.