从迭代器制作序列

Cur*_*mes 10 perl6

我正在尝试创建一个迭代器,然后从中构建一个序列,但它不会按我认为应该的方式运行.这是怎么回事?

这是我的基础课:

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,它似乎抓住了价值并给了我想要的东西,我只是想了解我看到的行为.

Bra*_*ert 7

我做了精确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)