我正在尝试创建一个迭代器,然后从中构建一个序列,但它不会按我认为应该的方式运行.这是怎么回事?
这是我的基础课:
class Foo {
has $.x = 0;
has $.max = 3;
method val() {
(++$!x > $!max) ?? () !! ($!x, "string $!x")
}
}
my $foo = Foo.new;
say $foo.val.perl for ^4;
# (1, "string 1")
# (2, "string 2")
# (3, "string 3")
# ()
Run Code Online (Sandbox Code Playgroud)
它只是迭代到max,然后return(),按照我认为的方式工作.
然后我从中构建一个迭代器,只需一个pull-one()方法.
class Foo-Iterator does Iterator {
has Foo $.foo;
method pull-one() {
$!foo.val || IterationEnd
}
}
my $iter = Foo-Iterator.new(foo => Foo.new);
$iter.pull-one.perl.say for ^4;
# (1, "string 1")
# (2, "string 2")
# (3, "string 3")
# IterationEnd
Run Code Online (Sandbox Code Playgroud)
它仍然按照我的预期行事.
如果我使用Seq访问它,它仍然可以正常工作:
.perl.say for Seq.new: Foo-Iterator.new(foo => Foo.new);
# (1, "string 1")
# (2, "string 2")
# (3, "string 3")
Run Code Online (Sandbox Code Playgroud)
这仍然是我期望看到的,Iterator返回的是同样的事情.
最后,我将Seq存储在@变量中并打印出结果:
my @seq = Seq.new: Foo-Iterator.new(foo => Foo.new);
.perl.say for @seq;
# $(4, "string 1")
# $(4, "string 2")
# $(4, "string 3")
Run Code Online (Sandbox Code Playgroud)
那是怎么回事?它似乎是使用变量的后期值而不是它在pull-one call()时所具有的值(字符串强制为值).做了Seq回击一个容器,而不是价值?这种懒惰是否在行动中,在请求之前它不会拉动,因此它会获得更高的价值?
如果我val()返回+$!x而不是返回$!x,它似乎抓住了价值并给了我想要的东西,我只是想了解我看到的行为.
我做了精确4个变为Foo:does Iterator,pull-one,IterationEnd,和我decont %!x用<>.
$!x当你真的想要传递容器内部的值时,你的方法是传递容器,所以它需要$!x<>.
您没有注意到其余代码的原因是数组赋值是唯一的eager.
我做了其余的更改,因为它已经有状态,并且它只能工作一次.这究竟Iterator应该如何运作.使用您的代码,添加另一个对象Iterator基本上只重命名方法是没有意义的.
class Foo does Iterator {
# ^-----------^
has $.x = 0;
has $.max = 3;
method pull-one() {
# ^------^
(++$!x > $!max) ?? IterationEnd !! ($!x<>, "string $!x")
# ^----------^ ^^
}
}
Run Code Online (Sandbox Code Playgroud)
现在用它
my $seq = Seq.new( Foo.new );
for $seq<> { .say }
# (1 string 1)
# (2 string 2)
# (3 string 3)
my @seq = Seq.new( Foo.new );
for @seq { .say }
# (1 string 1)
# (2 string 2)
# (3 string 3)
Run Code Online (Sandbox Code Playgroud)
假设你的例子太简单了,并且有一个很好的理由让Iterator你有一个单独的,为什么你有一个变异的val方法?
class Foo-Iterator {…}
class Foo does Iterable {
has $.max = 3;
method val ( $index ) {
($index > $!max) ?? () !! ($index, "string $index")
}
method iterator (){
# pass `self` for method calls or such
# (could pass internal data additionally/instead)
Foo-Iterator.new( :foo(self) )
}
}
class Foo-Iterator does Iterator {
# the mutating value
has $!x = 0;
# make it public only so we don't have
# to mess with `new` or `BUILD`
has $.foo is required;
# only have the mutating logic in this object
method pull-one() {
$!foo.val( ++$!x ) || IterationEnd
}
}
Run Code Online (Sandbox Code Playgroud)
现在用它.
# only one Foo object needed
my $foo = Foo.new;
# for Seq.new($foo.iterator) { .say }
for $foo<> { .say }
# (1 string 1)
# (2 string 2)
# (3 string 3)
for $foo<> { .say }
# (1 string 1)
# (2 string 2)
# (3 string 3)
my $iter-a = $foo.iterator;
my $iter-b = $foo.iterator;
say $iter-a.pull-one;
# (1 string 1)
say $iter-a.pull-one;
# (2 string 2)
say $iter-b.pull-one; # notice that $iter-b isn't tied to $iter-a
# (1 string 1)
my @seq = $foo<>;
for @seq { .say }
# (1 string 1)
# (2 string 2)
# (3 string 3)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
119 次 |
| 最近记录: |