Во время многозначной итерации, если у нас заканчиваются значения, последняя группа значений не будет обрабатываться в текущей версии Rakudo.

my @arr = 1, 2, 3, 4, 5, 6
for @arr -> $a, $b, $c, $d {
  say $a
  say $b
  say $c
  say $d
}

Результат

1
2
3
4

, который отбрасывает 5 и 6.

Итак, каким образом я могу получить элементы, которые отброшены?

6
hwding 28 Май 2017 в 10:36

2 ответа

Лучший ответ

Как отмечает @ choroba's ответ, ваш код фактически выдает ошибку в Perl 6.c.

Ошибка возникает на второй итерации, когда от входного массива остается только 5, 6, который нельзя сопоставить с подписью $a, $b, $c, $d, поскольку все четыре параметра в этой подписи являются обязательными.

Есть несколько способов заставить это работать:

A) Отметьте параметры как необязательные.

for @arr -> $a, $b?, $c?, $d? {
    say "---";
    say $a;
    say $b if $b.defined;
    say $c if $c.defined;
    say $d if $d.defined;
}

? означает необязательный - то есть, когда этому параметру не передается аргумент, ему присваивается значение Mu («наиболее неопределенное»). Обратите внимание, что нет необходимости отмечать параметр first как необязательный, потому что при нулевых элементах ввода оставленный цикл for завершается и не пытается ввести другую итерацию.
Вывод:

---
1
2
3
4
---
5
6

Б) Укажите значения по умолчанию для параметров.

for @arr -> $a, $b = 'default-B', $c = 'default-C', $d = 'default-D' {
    say ($a, $b, $c, $d);
}

Это то, что @choroba уже предложил. По сути, это еще один способ сделать параметры необязательными, но теперь с пользовательским значением вместо Mu в случае, если им не был передан аргумент.
Вывод:

(1 2 3 4)
(5 6 default-C default-D)

C) Используйте .rotor для обработки разбиения.

Использование for блока с многопараметрической сигнатурой - не единственный способ повторять список значений n-за-временем. Метод .rotor обеспечивает те же функциональные возможности в более функциональном стиле. По умолчанию он пропускает частичные итерации в конце, поэтому вам нужно предоставить ему параметр :partial, чтобы включить эту итерацию:

for @arr.rotor(4, :partial) -> @slice {
    say @slice;
}

Для каждой итерации @slice становится списком из 4 элементов, за исключением последней итерации, где может быть меньше элементов .. (Вы можете проверить @slice.elems внутри тела цикла, чтобы увидеть, сколько у вас получилось.)
Вывод:

(1 2 3 4)
(5 6)
7
smls 28 Май 2017 в 13:40

Пробуя в Rakudo Star, я только что установил:

===SORRY!=== Error while compiling /home/choroba/1.p6
Unexpected block in infix position (missing statement control word before the expression?)
at /home/choroba/1.p6:2
------> for @arr⏏ -> $a, $b, $c, $d {
    expecting any of:
        infix
        infix stopper

После добавления точек с запятой везде я получаю

1
2
3
4
Too few positionals passed; expected 4 arguments but got 2
  in block <unit> at /home/choroba/1.p6 line 2

Вы можете указать значения по умолчанию, если не хотите получать ошибку:

for @arr -> $a,
            $b = 'Missing b',
            $c = 'Missing c',
            $d = 'Missing d' {

В комментариях smls переменные также можно сделать необязательными:

for @arr -> $a, $b?, $c?, $d? {

Который будет работать так же, как при использовании $var = Mu.

5
choroba 28 Май 2017 в 16:41