Как присвоить .lines Seq переменной и выполнить итерацию по ней? - PullRequest
0 голосов
/ 28 сентября 2018

Назначение итератора для переменных, очевидно, ведет себя как 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 голосов
/ 28 сентября 2018

Назначение в Perl 6 всегда сводится к тому, чтобы поместить в что-то еще.

Назначение в Scalar ($ сигил) хранит назначаемую вещь в Scalarконтейнерный объект, то есть он будет рассматриваться как отдельный элемент;Вот почему for $item { } не будет выполнять итерацию.Есть различные способы преодолеть это;самый концептуально простой способ - использовать постфиксный оператор <>, который удаляет любой контейнер Scalar:

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

Также есть оператор скольжения ("flatten into"), который достигнет того же самого:

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 запускает его, только если мы находимся наПервая запись в текущем клоне закрытия.

0 голосов
/ 28 сентября 2018

Если вы хотите иметь возможность перебирать последовательность, вам нужно либо присвоить ее позиционному:

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

Или вы можете сказать итератору, что вы хотите обработатьданная вещь как итеративная:

.say for @$i

Или вы можете вставить ее в список для итератора:

.say for |$i

...