为迭代器分配变量显然会改变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之间的区别。
答案 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