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