如何将.lines Seq分配给变量并对其进行迭代?

时间:2018-09-28 15:33:52

标签: perl6 raku

为迭代器分配变量显然会改变Seq的行为。例如

use v6;

my $i = '/etc/lsb-release'.IO.lines;
say $i.WHAT;
say '/etc/lsb-release'.IO.lines.WHAT;
.say for $i;
.say for '/etc/lsb-release'.IO.lines;

导致:

(Seq)
(Seq)
(DISTRIB_ID=Ubuntu DISTRIB_RELEASE=18.04 DISTRIB_CODENAME=bionic DISTRIB_DESCRIPTION="Ubuntu 18.04.1 LTS")
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.1 LTS"

因此,一旦分配,我只会得到序列的字符串表示形式。我知道我可以使用.say for $i.lines来获得相同的输出,但是我不了解分配的迭代器和未分配的迭代器/ Seq之间的区别。

2 个答案:

答案 0 :(得分:13)

Perl 6中的赋值始终是将放入中。

分配到Scalar$标记)会将要分配的东西存储到Scalar容器对象中,这意味着它将被视为单个项目;这就是for $item { }不进行迭代的原因。有多种方法可以克服这个问题;从概念上讲,最简单的方法是使用<>后缀运算符,该运算符会剥离所有Scalar容器:

my $i = '/etc/lsb-release'.IO.lines;
.say for $i<>;

还有滑动操作符(“展平为”),将实现相同的效果:

my $i = '/etc/lsb-release'.IO.lines;
.say for |$i;

分配给Array时-除非右侧标记为惰性,否则将对其进行迭代并将每个元素存储到Array中。因此:

my @i = '/etc/lsb-release'.IO.lines;
.say for @i;

会起作用,但是它将在循环开始之前热切地将所有行读入@i中。对于小文件,这是可以的,但对于大文件,则不太理想,因为在大文件中,我们可能更喜欢懒惰地工作(也就是说,一次只将一部分文件拉到内存中)。一个人可以尝试:

my @i = lazy '/etc/lsb-release'.IO.lines;
.say for @i;

但这对保留问题没有帮助;这只是意味着随着迭代的进行,数组将从文件中延迟填充。当然,有时我们可能会想要多次浏览这些行,在这种情况下,将分配给Array是最好的选择。

通过对比,声明一个符号并将其绑定到该符号:

my \i = '/etc/lsb-release'.IO.lines;
.say for i;

根本不是“放入”操作;它只是使符号i精确地指代lines返回的内容。这比仅将其再次放入Scalar容器中要清晰得多。对读者来说,这也容易一些,因为my \foo = ...永远不会反弹,因此读者无需再寻找代码中任何潜在的变化。

最后,值得一提的是,my \foo = ...表单实际上是绑定而不是赋值。 Perl 6允许我们使用=运算符来编写它,而不是强制:=,即使在这种情况下语义是:=语义。这只是其中带有初始化程序的声明与常规分配(例如, has $!foo = rand实际上在每个对象实例上运行分配,而state $foo = rand仅在我们位于当前闭包克隆的第一个条目上时才运行它。

答案 1 :(得分:6)

如果您希望能够遍历序列,则需要将其分配给一个位置:

z_scores.append(z_score)

或者您可以告诉迭代器您想要将给定的事物视为可迭代的:

my @i = '/etc/lsb-release'.IO.lines; .say for @i;

或者您可以将其放到迭代器的列表中:

.say for @$i