Perl 6 - 是否可以创建一个设置元属性的属性特征?

时间:2017-10-13 17:13:31

标签: object attributes immutability traits perl6

我尝试创建属性特征。用例是将类的某些属性标记为" crudable"在对象到文档映射的上下文中,而其他则不是。

role crud {
    has Bool $.crud is default(True);
}

multi trait_mod:<is>(Attribute $a, crud, $arg) {
    $a.container.VAR does crud($arg);
}

class Foo {
    has $.bar is rw;

    # Provide an extra nested information
    has $.baz is rw is crud(True);
}

通过阅读和改编some example code,我设法得到了一些似乎可以做我想要的东西。这是a snippet with test case

当我实例化一个新的Foo对象并设置$.bar属性(is而非crud)时,它看起来像是:

.Foo @0
├ $.bar is rw = 123456789
└ $.baz is rw = .Scalar+{crud} @1
  └ $.crud +{crud} = True

我从中理解的是$.baz属性得到了我称之为元属性的独立于其潜在价值的东西。

对我来说这很好看(如果我理解我在这里做了什么,我的特质使用不是一个肮脏的黑客)。有可能达到$foo.baz.crud True。虽然,我不太了解.Scalar+{crud}的含义,以及我是否可以在那里设置一些内容以及如何设置。

当我尝试设置$.baz实例属性时,会返回此错误:

Cannot modify an immutable Scalar+{crud} (Scalar+{crud}.new(crud => Bool::True))
  in block <unit> at t/08-attribute-trait.t line 30

注意:这是我设法获得的工作解决方案最接近的事情。对于实例化的Foo类的不同实例,我不需要不同的crud设置。

我从不想改变布尔值,实际上,一旦对象被实例化,只是将它提供给具有is crud 的属性。我甚至不想将TrueFalse值作为参数传递:如果默认情况下可以将布尔特征属性设置为True,那就足够了。我没有设法做到这一点,比如:

multi trait_mod:<is>(Attribute $a, :$crud!) {
    # Something like this
    $a.container.VAR does set-crud;
}

class Foo {
    has $.bar is rw;
    has $.baz is rw is crud;
}

我想做一些不可能的事吗?我如何调整此代码以实现此用例?

1 个答案:

答案 0 :(得分:4)

这里有几件事情。首先,trait_mod的签名看起来是错误的。其次,当特征的名称与现有角色相同时,似乎存在不良交互。我相信这应该是一个NYI异常,但显然它在解析时出错,或者在尝试生成错误消息时出错。

无论如何,我认为这就是你想要的:

role CRUD {};  # since CRUD is used as an acronym, I chose to use uppercase here

multi trait_mod:<is>(Attribute:D $a, :$crud!) { # note required named attribute!
    $a.^mixin: CRUD if $crud;  # mixin the CRUD role if a True value was given
}

class A {
    has $.a is crud(False);  # too bad "is !crud" is invalid syntax
    has $.b is crud;
}

say "$_.name(): { $_ ~~ CRUD }" for A.^attributes; # $!a: False, $!b: True

希望这有帮助。