从the example in the Iterable doc page
开始role DNA does Iterable {
method iterator(){ self.comb.iterator }
};
my @a does DNA = 'GAATCC';
.say for @a; # OUTPUT: «GAATCC»
我发现使用@
声明它很奇怪,因此我将其更改为自然声明字符串的方式$
:
my $a does DNA = 'GAATCC';
但是失败了,有点令人困惑的“无法分配给不可变的值”。无需现场指派,所以我们可以这样做:
my $a = 'GAATCC';
$a does DNA;
.say for $a;
这只是为了以后留下混合。但这只是打印字符串,而没有注意Iterable
mixin。我们明确地称之为:
.say for $a.iterator;
它与以前完全相同,只打印$a.iterator
的值,而不实际调用函数:
<anon|69>.new
这看起来像the same thing it's going on in this other question。基线问题是我不明白Iterable真正做了什么角色,for
真正做了什么以及何时在某个对象上调用iterator
。有什么想法吗?
答案 0 :(得分:8)
我不认为这条线符合您的想法:
my @a does DNA = 'GAATCC';
与以下内容相同:
my @a := [ 'GAATCC', ];
@a does DNA;
基本上.comb
调用将数组强制转换为Str,然后将其拆分为字符。
如果您改为这样做:
my @a = 'GAATCC' but DNA;
与
基本相同my @a := Seq.new(('GAATCC' but DNA).iterator).Array;
请注意,@
个变量存储Positional
值不是Iterable
值。
你想要的是
my $a = 'GAATCC' but DNA;
$a.map: &say;
如果您希望能够使用for
,则无法使用带$
sigil的变量
my \a = 'GAATCC' but DNA;
.say for a;
您可能希望将Seq
list
List
等方法添加到DNA
。
role DNA does Iterable {
method iterator(){
self.comb.iterator
}
method Seq(){
Seq.new: self.iterator
}
method list(){
# self.Seq.list
List.from-iterator: self.iterator
}
}
my $a = 'GAATCC' but DNA;
.say for @$a;
答案 1 :(得分:6)
您的问题标题指向错误。这个答案涵盖了错误以及您提出的其他隐含和明确的问题。
失败了,有点令人困惑&#34;无法分配给不可变的值&#34;。
我认为这是一个错误。让我们从一些有用的代码开始:
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
类型$a
是,你实际得到的是当前已分配给标量的值的类型(它的值为#34;包含&#34;)。您需要VAR
才能访问容器 BOUND到$ 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混合在一起与the decision process for
uses about whether to call its argument's .iterator
method无关。
让我们明确地调用它...打印
$a.iterator
的值,而不实际调用函数:
.say for $a.iterator;
它确实会调用您DNA
角色的.iterator
方法。但是,在.iterator
角色的self.comb
方法返回的DNA
末尾有另一个 iterator
来电,所以你&#39 ;重新.say
该次要.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
属性,或者使用=
将值分配给容器时使用。{/ p>
但相反,你得到:
is trait on $-sigil variable not yet implemented. Sorry.
因此,今天最接近= 'string'
改变$a
的理想是使用:= DNA.new('string')
进行绑定,就像在你的要点中所做的那样。
请注意,可以将任意复合容器绑定到@
和%
sigil变量。所以你可以看到事情最终会如何发挥作用。