您的问题的标题指向一个错误。此答案涵盖了该错误以及您提出的其他隐式和显式问题。
背景
以有点令人困惑的“无法分配给不可变的值”而失败。
我认为这是一个错误。让我们从一些有效的代码开始:
my $a = 42;
say $a; # 42
say WHAT $a; # (Int) type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar) type of VARIABLE currently BOUND to $a
$a = 42; # works fine
在my 声明中$a 绑定到一个新的Scalar container。 Scalar 容器通常会隐藏自己。如果你问WHAT type $a 是,你实际上得到了当前分配给标量的值的类型(它“包含”的值)。您需要VAR 才能访问绑定到$a 的容器。当您将 = 分配给 Scalar 容器时,您会将分配的值复制到容器中。
role foo {}
$a does foo; # changes the VALUE currently ASSIGNED to $a
# (NOT the VARIABLE that is BOUND to $a)
say $a; # 42 mixed in `foo` role is invisible
say WHAT $a; # (Int+{foo}) type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar) type of VARIABLE currently BOUND to $a
$a = 99; say $a; # 99
does 将foo 角色混合到42 中。您仍然可以分配给 $a,因为它仍然绑定到 Scalar。
注意does 的这两种用法如何产生截然不同的效果:
my $a does foo; # mixes `foo` into VARIABLE bound to $a
$a does foo; # mixes `foo` into VALUE assigned to $a
错误
$a.VAR does foo; # changes VARIABLE currently BOUND to $a (and it loses the 42)
say $a; # Scalar+{foo}.new VALUE currently ASSIGNED to $a
say WHAT $a; # (Scalar+{foo}) type of VALUE currently ASSIGNED to $a
say WHAT VAR $a; # (Scalar+{foo}) type of VARIABLE currently BOUND to $a
$a = 'uhoh'; # Cannot assign to an immutable value
does 将foo 角色混合到绑定到$a 的Scalar 中。似乎带有 mixin 的 Scalar 不再成功地用作容器并且分配失败。
目前在我看来这像是一个错误。
my $b does foo; # BINDS mixed in VARIABLE to $b
$b = 'uhoh'; # Cannot assign to an immutable value
my $b does foo 与my $b; $b.VAR does foo; 的结果相同,因此您会遇到与上述相同的问题。
其他你感到困惑的事情
my $a = 'GAATCC';
$a does DNA;
.say for $a;
只打印字符串,不关注Iterable mixin。
因为$a VARIABLE 仍然绑定到Scalar(如上面的背景 部分所述),现在混入DNA 角色的VALUE 与@ 无关987654322@.
让我们显式调用它...打印$a.iterator 的值,而不实际调用函数:
.say for $a.iterator;
它确实调用了您的DNA 角色的.iterator 方法。但这在DNA 角色的iterator 方法返回的self.comb 末尾有另一个 .iterator 调用,所以你是.saying 第二个.iterator。
当今有效的解决方案
我认为布拉德的回答很好地涵盖了您的大部分选择。
如果你想使用$ sigil,我认为你漂亮的does DNA gist 与今天的P6 一样好。
一种可能有一天会奏效的解决方案
在理想情况下,P6 设计中的所有优点都将在 6.c 和 Perl 6 的 Rakudo 编译器实现中得到充分体现。也许这将包括编写此代码并获得所需内容的能力:
class DNA is Scalar does Iterable { ... }
my $a is DNA = 'GAATCC';
.say for $a;
... 代码与 gist 中的代码大致相同,只是 DNA 类将是一个标量容器,因此 new 方法将改为 STORE 方法或类似方法当使用= 将值分配给容器时,会将传递的值分配给$!value 属性或类似属性。
但相反,你会得到:
is trait on $-sigil variable not yet implemented. Sorry.
因此,您今天最接近理想的 = 'string' 以更改 $a 是使用 := DNA.new('string') 绑定,就像您在要点中所做的那样。
请注意,您可以将任意复合容器绑定到@ 和% sigil 变量。所以你可以看到事情最终应该如何运作。