Назначить Seq (Seq) в массивы - PullRequest
11 голосов
/ 05 июня 2019

Каков правильный синтаксис для назначения Seq (Seq) в несколько типизированных массивов без предварительного присвоения Seq скаляру? Seq должен быть как-то сплющен? Это не удается:

class A { has Int $.r }

my A (@ra1, @ra2);

#create two arrays with 5 random numbers below a certain limit

#Fails: Type check failed in assignment to @ra1; expected A but got Seq($((A.new(r => 3), A.n...)
(@ra1, @ra2) =
   <10 20>.map( -> $up_limit {
        (^5).map({A.new( r => (^$up_limit).pick ) })
    });

Ответы [ 2 ]

12 голосов
/ 06 июня 2019

TL; DR Привязка выполняется быстрее, чем назначение, поэтому, возможно, это лучшее решение для вашей проблемы:

:(@ra1, @ra2) := <10 20>.map(...);

Назначение / копирование

Упрощение,Ваш нерабочий код:

(@listvar1, @listvar2) = list1, list2;

В инфиксе P6 = означает присвоение / копирование списка значений справа от = в один или несколько из контейнер переменных слева от =.

Если переменная слева связана с Scalar контейнером , то она примет одинвещь.Затем процесс копирования начинает нацеливаться на следующую переменную контейнера.

Если переменная слева связана с Array контейнером , то она примет все оставшиеся значения.Итак, ваша первая переменная массива получает как list1, так и list2.Это не то, что вы хотите.

Упрощенно, вот ответ Кристофа:

@listvar1, @listvar2 Z= list1, list2;

Отложив = на мгновение, Z - это инфиксная версия zip рутина .Это как ( физический zip , соединяющий последовательные аргументы слева и справа. При использовании с оператором он применяет этот оператор к паре. Таким образом, вы можете прочитать выше Z= как:

@listvar1 = list1;
@listvar2 = list2;

Работа выполнена.

Но назначение в Array контейнеров влечет за собой:

  • По отдельности копирование какмного отдельных элементов списка, так как в контейнерах. (В коде в вашем примере list1 и list2 содержат 5 элементов каждый, так что всего будет 10 операций копирования.)

  • Принудительное изменение размеров контейнеров для размещения элементов.

  • Удвоение памяти, используемой элементами (исходные элементы списка и скопированные дубликаты)в Array элементов).

  • Проверка того, что тип каждого элемента соответствует ограничению на тип элемента.

Назначение в целом многомедленнее и требует больше памяти, чем привязка ...

Binding

:(@listvar1, @listvar2) := list1, list2;

Оператор := связывает аргументы справа от того, что слева от него.

Если естьодна переменная слева, тогда все особенно просто.После привязки переменная теперь относится именно к тому, что справа.(Это особенно просто и быстро - быстрая проверка типа, и она сделана.)

Но в нашем случае это не так.

Binding также принимает автономный литерал подписи слева от него.:(...) в моем ответе - автономный Signature литерал.

(подписи обычно прикрепляются к подпрограмме без префикса двоеточия. Например, в sub foo (@var1, @var2) {} (@var1, @var2) part - это сигнатура, прикрепленная к подпрограмме foo. Но, как вы можете видеть, можно написать сигнатуру отдельно и дать P6 знать, что это сигнатура, добавив перед парой двоеточия двоеточие.в подписи, должно быть, уже было объявлено.)

Если слева находится литерал подписи, то привязка происходит в соответствии с той же логикой, что и при привязке аргументов в обычных вызовах к подписи принимающей подпрограммы.(Действительно, он использует тот же путь кода в компиляторе.)

Таким образом, в результате переменные получают значения, которые они будут иметь внутри этого подпрограммы:

sub foo (@listvar1, @listvar2) { }
foo list1, list2;

, чтосказать, что эффект такой же, как:

@listvar1 := list1;
@listvar2 := list2;

Опять же, как и с ответом Кристофа, работа выполнена.

Но на этот раз мы избежали большинства накладных расходов, описанных вконец предыдущего раздела.

11 голосов
/ 05 июня 2019

Не совсем уверен, что это так, но кажется, что обе ваши последовательности сохраняются в @ra1, а @ra2 остается пустым. Это нарушает ограничение типа.

Что работает

@ra1, @ra2 Z= <10 20>.map(...);
...