此示例取from roast
,尽管已经存在8年了:
role doc { has $.doc is rw }
multi trait_mod:<is>(Variable $a, :$docced!) {
$a does doc.new(doc => $docced);
}
my $dog is docced('barks');
say $dog.VAR;
这将返回Any
,而没有任何角色的混合。尽管特质不会出错,但显然没有办法进入“ doc”部分。有想法吗?
答案 0 :(得分:5)
(此答案基于@guifa的答案和JJ的评论。)
在可变特征中使用的习惯用法基本上是$var.var.VAR
。
虽然大声说起来听起来很有趣,但看起来也很疯狂。不是,但是至少需要解释,并且也许某种形式的认知/句法缓解。
以下是有关如何理解的简短版本:
$var
作为trait参数的名称是有意义的,因为它绑定到Variable
,即变量的编译器视图视图。
.var
来访问给定编译器视角的变量的用户视角视图。
如果变量是Scalar
,那么还需要.VAR
来获取变量,而不是包含的值。 (如果它不是Scalar
,则无害。)
我将在一个月中更详细地说明上述内容,但首先,如何减轻负担?
也许我们可以引入一种新的Variable
方法。但是,除非该方法的名称如此好,以至于根本不需要在答案的下一部分中使用.var.VAR
咒语解释,否则这将是一个错误。
但是我怀疑这样的名字存在。我想出的每个名字都会使事情变得更糟。即使我们想出了一个完美的名字,充其量还是值得的。
您对原始示例的复杂性感到震惊。有一个$var.var.VAR
特征,称为is
特征。因此,也许需要一个例程来抽象这种复杂性和does
。但是总有一些方法可以降低双重性状的复杂性,例如:
$var.var.VAR
role doc[$doc] { has $.doc is rw = $doc}
my $dog does doc['barks'];
say $dog.doc; # barks
但是
$var.var.VAR
已经是一个变量。为什么有这么多$v
和var
?
的确。 VAR
绑定到$v
类的实例。这还不够吗?
否,因为Variable
:
用于存储元数据关于变量的编译过程。 (也许它应该被称为Variable
?只是在开玩笑。Metadata-About-A-Variable-Being-Compiled
在特征签名中看起来不错,而且更改其名称也不会阻止我们使用和解释Variable
这个习惯用法。)
不是我们要寻找的机器人。我们需要该变量的用户视角。已经被声明和编译的代码,然后被用作用户代码的一部分。 (例如,$var.var.VAR
行中的$dog
。即使它是say $dog...
,所以它还是在编译时运行的,BEGIN say $dog...
仍会 指的是绑定到用户的视图容器或值的符号,而不是仅与数据相关的编译器的视图的$dog
实例em>变量。)
使编译器和编写特质的人的工作更加轻松。但这要求特征编写者访问变量的用户视角,以访问或更改用户的视角。 Variable
的{{1}}属性存储该用户的眼睛视图。 (我注意到,烘烤测试具有一个.var
属性,您已省略了该属性。现在显然已将其重命名为Variable
。我的猜测是,这是因为变量可能绑定到不可变值而不是容器,所以名称.container
被认为具有误导性。)
.var
?让我们从原始代码的变体开始,然后继续。我将从.container
切换到$var.var.VAR
,然后从$dog
行中删除@dog
:
.VAR
这几乎有效。一个微小的更改,它会起作用:
say
我要做的就是在multi trait_mod:<is>(Variable $a, :$docced!) {
$a does role { has $.doc = $docced }
}
my @dog is docced('barks');
say @dog.doc; # No such method 'doc' for invocant of type 'Array'
行中添加multi trait_mod:<is>(Variable $a, :$docced!) {
$a.var does role { has $.doc = $docced }
}
my @dog is docced('barks');
say @dog.doc; # barks
。在您的原文中,该行正在修改变量的编译器视图,即绑定到.var
的{{1}}对象。不会修改用户的视线视图,即绑定到... does role ...
的{{1}}。
据我所知,现在对于数组和哈希之类的复数容器,一切都可以正常工作:
Variable
但是当我们尝试使用$a
变量时:
Array
我们得到:
@dog
这是因为@dog[1] = 42;
say @dog; # [(Any) 42]
say @dog.doc; # barks
返回的是用户眼睛视图变量通常返回的内容。使用Scalar
,您将获得my $dog is docced('barks');
。但是使用Cannot use 'does' operator on a type object Any.
,您将得到.var
包含的值。 (这是P6的基本方面。效果很好,但是您必须在这种情况下知道它。)
因此,要使它再次出现[em] ,我们还必须添加几个Array
。对于Array
以外的其他任何内容,Scalar
都是“禁止操作”,因此对添加Scalar
以外的其他案例没有任何危害:
.VAR
现在Scalar
案例似乎也可以起作用:
.VAR
(出于相同的原因,我不得不在Scalar
行中重新引入multi trait_mod:<is>(Variable $a, :$docced!) {
$a.var.VAR does role { has $.doc = $docced }
}
。)
如果一切都好,那将是答案的结束。
但是有些东西坏了。如果我们尝试初始化Scalar
变量:
my $dog is docced('barks');
say $dog.VAR.doc; # barks
我们会看到:
.VAR
如@guifa所述,I stumbled on a while back:
似乎带有混入的
say
不再成功地充当容器,并且分配失败。在我看来,这目前似乎是一个错误。
答案 1 :(得分:3)
答案不令人满意,但是也许您可以从中获得进步
role doc {
has $.doc is rw;
}
multi trait_mod:<is>(Variable:D $v, :$docced!) {
$v.var.VAR does doc;
$v.var.VAR.doc = $docced;
}
say $dog; # ↪︎ Scalar+{doc}.new(doc => "barks")
say $dog.doc; # ↪︎ barks
$dog.doc = 'woofs'; #
say $dog; # ↪︎ Scalar+{doc}.new(doc => "woofs")
不幸的是,这有些不对劲,应用特性似乎会使变量变得不可变。