这个例子是采取从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;
Run Code Online (Sandbox Code Playgroud)
这将返回Any,而不会混入任何角色。尽管特质不会出错,但显然没有办法进入“ doc”部分。任何的想法?
(此答案基于@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
Run Code Online (Sandbox Code Playgroud)
$var.var.VAR但是
$v已经是一个变量了。为什么有这么多var和VARS'
确实。$v绑定到Variable该类的实例。这还不够吗?
不,因为Variable:
用于在编译变量时存储有关变量的元数据。(也许它应该被称为?只是在开玩笑。在特征签名上看起来不错,并且更改其名称也不会阻止我们继续使用和解释该习语。)Metadata-About-A-Variable-Being-CompiledVariable$var.var.VAR
不是我们要寻找的机器人。我们需要用户对变量的看法。已经被声明和编译的代码,然后被用作用户代码的一部分。(例如,$dog在该行say $dog...。即使有BEGIN say $dog...,所以它跑在编译时,$dog将仍然指的是绑定到一个user's眼视图容器或价值的象征。它不会指Variable这仅仅是实例编译器变量相关数据的直观视图。)
使编译器和编写特质的人更加轻松。但这要求特征编写者访问变量的用户视角,以访问或更改用户的视角。该用户视线.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'
Run Code Online (Sandbox Code Playgroud)
这几乎可行。一个微小的变化,它的工作原理是:
multi trait_mod:<is>(Variable $a, :$docced!) {
$a.var does role { has $.doc = $docced }
}
my @dog is docced('barks');
say @dog.doc; # barks
Run Code Online (Sandbox Code Playgroud)
所有我做的就是添加一个.var到... does role ...线。在您的原始代码中,该行正在修改变量的编译器视图,即Variable绑定到的对象$a。它不会修改变量的用户视图,即Array绑定到@dog。
据我所知,现在对于数组和哈希之类的复数容器,一切都可以正常工作:
@dog[1] = 42;
say @dog; # [(Any) 42]
say @dog.doc; # barks
Run Code Online (Sandbox Code Playgroud)
但是,当我们尝试使用Scalar变量时:
my $dog is docced('barks');
Run Code Online (Sandbox Code Playgroud)
我们得到:
Cannot use 'does' operator on a type object Any.
Run Code Online (Sandbox Code Playgroud)
这是因为.var无论用户的眼睛视图变量通常返回什么,它都会返回。有了,Array你得到了Array。但是有了a,Scalar您将获得Scalar包含的值。(这是P6的基本方面。它很好用,但是您必须在这种情况下知道它。)
因此,要使它再次显示正常工作,我们还必须添加一对夫妇.VAR。对于除以外的任何Scalar一个.VAR是“无操作”,所以它没有伤害比其他情况下,Scalar将其添加:
multi trait_mod:<is>(Variable $a, :$docced!) {
$a.var.VAR does role { has $.doc = $docced }
}
Run Code Online (Sandbox Code Playgroud)
现在,这种Scalar情况似乎也起作用了:
my $dog is docced('barks');
say $dog.VAR.doc; # barks
Run Code Online (Sandbox Code Playgroud)
(我不得不重新引入.VAR在say出于同样的原因,我不得不把它添加到行$a.var.VAR ...线。)
如果一切都好,那将是答案的结尾。
但是有些东西坏了。如果我们尝试初始化Scalar变量:
my $dog is docced('barks') = 42;
Run Code Online (Sandbox Code Playgroud)
我们会看到:
Cannot assign to an immutable value
Run Code Online (Sandbox Code Playgroud)
Scalar带有mixin的似乎不再成功用作容器,并且分配失败。在我看来,这目前似乎是一个错误。
| 归档时间: |
|
| 查看次数: |
115 次 |
| 最近记录: |