为变量分配迭代器显然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;
Run Code Online (Sandbox Code Playgroud)
结果是:
(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"
Run Code Online (Sandbox Code Playgroud)
所以一旦分配,我只得到序列的字符串表示.我知道我可以使用.say for $i.lines相同的输出,但我不明白分配和未分配的迭代器/ Seq之间的区别.
Jon*_*ton 13
Perl 6中的赋值始终是将某些内容放入其他内容中.
分配到Scalar($sigil)将被分配的东西存储到Scalar容器对象中,这意味着它将被视为单个项目; 这就是为什么for $item { }不进行迭代的原因.有各种方法可以克服这个问题; 最概念上最简单的方法是使用<>postfix运算符,它剥离任何Scalar容器:
my $i = '/etc/lsb-release'.IO.lines;
.say for $i<>;
Run Code Online (Sandbox Code Playgroud)
滑动操作员("压平")也将实现相同的目的:
my $i = '/etc/lsb-release'.IO.lines;
.say for |$i;
Run Code Online (Sandbox Code Playgroud)
分配到Array遗嘱 - 除非右侧标记为懒惰 - 迭代它并将每个元素存储到遗嘱中Array.从而:
my @i = '/etc/lsb-release'.IO.lines;
.say for @i;
Run Code Online (Sandbox Code Playgroud)
会工作,但它会@i在循环开始之前急切地读取所有行.对于小文件来说这是可以的,但对于大文件来说不太理想,我们可能更喜欢懒惰地工作(也就是说,一次只将文件拉入内存).有人可能会尝试:
my @i = lazy '/etc/lsb-release'.IO.lines;
.say for @i;
Run Code Online (Sandbox Code Playgroud)
但这对保留问题没有帮助; 它只是意味着当迭代发生时,数组将从文件中延迟填充.当然,有时我们可能想要多次遍历这些行,在这种情况下,分配到一个Array将是最好的选择.
相比之下,声明符号并将其绑定到:
my \i = '/etc/lsb-release'.IO.lines;
.say for i;
Run Code Online (Sandbox Code Playgroud)
根本不是"投入"运作; 它只是使符号i指的是什么lines返回.这比将它放入Scalar容器只是为了再次取出它更清楚.它对读者来说也更容易一些,因为my \foo = ...它永远不会被反弹,因此读者不需要在代码中查找任何可能的更改.
作为最后一点,值得知道my \foo = ...表单实际上是一个绑定,而不是一个赋值.Perl 6允许我们用=运算符而不是强制来编写它:=,即使在这种情况下语义是:=语义.这只是许多情况中的一种情况,其中具有初始化程序的声明与正常赋值略有不同,例如,has $!foo = rand实际上在每个对象实例化上运行赋值,而state $foo = rand仅在我们处于当前闭包的第一个条目时才运行它克隆.
如果您希望能够迭代序列,则需要将其分配给位置:
my @i = '/etc/lsb-release'.IO.lines;
.say for @i;
或者您可以告诉迭代器您希望将给定的东西视为可迭代的:
.say for @$i
或者您可以将其滑入迭代器的列表中:
.say for |$i